Shell 如何使用sed替换文件中多次出现的变量?

Shell 如何使用sed替换文件中多次出现的变量?,shell,sed,makefile,Shell,Sed,Makefile,我已经在编写一个脚本来替换shell脚本中Makefile中变量“SUBDIRS”的值。 我使用了下面的命令,它工作正常,但在第一次出现“SUBDIRS”后退出,并且makefile不完整 sed -z -i "s/\(SUBDIRS = \).*/\1$(tr '\n' ' ' < changed_fe_modules.log)\n/g" Makefile sed-z-i“s/\(SUBDIRS=\)./\1$(tr'\n''”

我已经在编写一个脚本来替换shell脚本中Makefile中变量“SUBDIRS”的值。 我使用了下面的命令,它工作正常,但在第一次出现“SUBDIRS”后退出,并且makefile不完整

 sed -z -i "s/\(SUBDIRS = \).*/\1$(tr '\n' ' ' < changed_fe_modules.log)\n/g" Makefile
sed-z-i“s/\(SUBDIRS=\)./\1$(tr'\n''”
现在我想保持Makefile的原样,只替换3次出现的“SUBDIRS=abcdefgh”并正确更新Makefile

请建议如何替换所有3个引用,并将Makefile端到端保留为原始文件

Makefile输入示例:

Makefile所需的输出示例:

现在,当前命令给了我以下输出:它在第一次替换后退出,文件不完整

 sed -z -i "s/\(SUBDIRS = \).*/\1$(tr '\n' ' ' < changed_fe_modules.log)\n/g" Makefile

这将非常困难

您看到这种行为的原因是您正在对sed使用
-z
选项。
-z
选项使用NUL字符分隔行,而不是换行符。这意味着为了sed的模式匹配,整个文件(直到第一个NUL字符,这里没有)被视为一条“线”

所以这个正则表达式:

\(SUBDIRS = \).*
此处的
*
匹配第一个
子项=
匹配后的整个文件其余部分。然后用
changed\u fe\u modules.log
文件的内容替换文件的其余部分。在那之后,没有什么可以匹配的了,所以sed就完成了

如果您的原始makefile在一行上列出了所有子曲面,而不使用反斜杠/换行分隔符,那么这将很简单;您只需使用:

sed -i "s/^SUBDIRS = .*/SUBDIRS = $(tr '\n' ' ' < changed_fe_modules.log)/" Makefile
sed-i“s/^SUBDIRS=.*/SUBDIRS=$(tr'\n'
如果必须使用反斜杠/换行符,则可能无法使用sed进行此更改。您需要使用更强大的工具,如Perl,它具有非贪婪匹配功能

埃塔

您也可以在纯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
new\u subdirs=$(tr'\n'Makefile.new
mv-f Makefile.new Makefile

(注意,完全未经测试)

给出
Makefile
的示例数据和您的预期输出。@Utsav更新了我的问题,提供了更多详细信息。为什么要以重复多次相同的SUBDIRS语句结束?在awk中,您尝试执行的任何操作都是微不足道的,但您必须添加简洁、可测试的示例输入和预期输出(即文本,而不是文本的照片!),并添加awk标记以获得帮助。感谢您的解释。这就更清楚了。我将看看我是否可以在这里使用任何其他语言,因为我的脚本的其余部分是在bash中。