我已经在编写一个脚本来替换变量的值" SUBDIRS"在shell脚本的Makefile中。 我使用下面的命令,它工作正常,但在第一次出现" SUBDIRS"和makefile不完整。
sed -z -i "s/\(SUBDIRS = \).*/\1$(tr '\n' ' ' < changed_fe_modules.log)\n/g" Makefile
现在我想保留我的Makefile,并且只替换3次&#34; SUBDIRS = abcdefgh&#34;并正确更新Makefile。
请建议如何替换所有3次出现并保持Makefile也以原始方式结尾。
Makefile输入样本:
Makefile所需的输出样本:
现在,当前命令给我低于输出:它在第一次替换后退出,文件不完整。
答案 0 :(得分:0)
这很难做到。
您看到此行为的原因是您在sed中使用-z
选项。 -z
选项用NUL字符分隔行,而不是换行符。这意味着整个文件(直到第一个NUL字符,这里没有一个)被视为单个“行”,用于sed的模式匹配。
所以这个正则表达式:
\(SUBDIRS = \).*
此处的.*
匹配第一个SUBDIRS =
匹配后的整个文件的其余部分。然后用changed_fe_modules.log
文件的内容替换文件的其余部分。之后没有什么可以匹配,所以sed就完成了。
如果您的原始makefile在一行中列出了所有SUBDIRS,而不是使用反斜杠/换行符分隔符,那么它很简单;你可以使用:
sed -i "s/^SUBDIRS = .*/SUBDIRS = $(tr '\n' ' ' < changed_fe_modules.log)/" Makefile
如果你必须使用反斜杠/换行符,你可能无法使用sed进行此更改。你需要使用像Perl这样功能更强大的东西,它具有非贪婪的匹配功能。
ETA
您也可以在普通shell中编写它:
new_subdirs=$(tr '\n' ' ' < changed_fe_modules.log)
line_cont=false
in_subdirs=false
while read -r line; do
if $line_cont; then
case $line in
(*\\) : still continuing ;;
(*) line_cont=false ;;
esac
$in_subdirs || printf '%s\n' "$line"
continue
fi
case $line in
(SUBDIRS =*)
echo "SUBDIRS = $new_subdirs"
in_subdirs=true ;;
(*) printf '%s\n' "$line"
in_subdirs=false ;;
esac
case $line in
(*\\) line_cont=true ;;
esac
done < Makefile > Makefile.new
mv -f Makefile.new Makefile
(注意,完全未经测试)