如何用sed实现将bash脚本中的source语句替换为对应文件内容?
如何用sed实现将bash脚本中的source语句替换为对应文件内容?
嘿,你的思路方向是对的,但问题出在shell命令的执行顺序上——你写的$(cat '\1')会在sed开始工作之前就被shell提前解析了,这时候sed的捕获组\1还根本没产生,shell会把'\1'当成一个字面量的文件名去读取,而这个文件显然不存在,所以替换出来自然是空内容啦。
下面给你两种可行的解决方案,根据你的环境选就行:
方法一:用GNU sed的e命令(推荐,简洁)
大部分Linux系统默认的GNU sed支持e修饰符,它会把替换后的字符串当成命令执行,然后用命令的输出替换原来的行。修改后的命令如下:
sed -E 's|^source (./.*)|cat \1|e' "$1" > ./test
细节说明:
-E:启用扩展正则表达式,这样括号()不需要转义,写起来更清爽;^source (./.*):精准匹配以source开头的行,捕获后面的相对路径文件名;e:执行替换后的cat \1命令,把对应文件的内容输出,替换掉原来的source行;- 记得给
$1加双引号,避免文件名里有空格时出现异常。
如果你的source行还有额外参数(比如source ./hello arg1),可以把正则调整成只捕获文件名部分:
sed -E 's|^source (./[^ ]*).*|cat \1|e' "$1" > ./test
方法二:用bash循环处理(兼容性更好)
如果你的环境里没有GNU sed(比如某些BSD系统),可以用bash的循环逐行处理,兼容性拉满:
#!/bin/bash # 读取输入文件的每一行,保留原格式 while IFS= read -r line; do # 判断当前行是否是source语句 if [[ $line =~ ^source (./.*) ]]; then # 如果是,就输出对应文件的内容 cat "${BASH_REMATCH[1]}" else # 不是的话,直接输出原行 echo "$line" fi done < "$1" > ./test
把这段代码保存成脚本(比如compiler.sh),然后给它加执行权限chmod +x compiler.sh,运行方式和你原来一样:./compiler.sh ./filetocompile
再回头说你的原命令问题
你原来写的:
sed 's|source \(\.\/.*\)|'$(cat '\1')'|g' $1 > ./test
shell会先解析$(cat '\1'),这时候sed还没开始处理任何行,所以'\1'就是一个普通字符串,cat尝试打开名为\1的文件(shell会去掉单引号,实际找的是\1这个文件),找不到就输出空,所以sed最终执行的是s|source \(\.\/.*\)||g,把source行直接替换成空,自然就只剩空行啦。
备注:内容来源于stack exchange,提问作者Harkhenon
相关产品推荐
相关产品推荐

