【问题标题】:Bash/sed string replace with contents of file (containing newlines)Bash/sed 字符串替换为文件内容(包含换行符)
【发布时间】:2013-12-22 02:32:20
【问题描述】:

针对 Bash ninjas 的问题:我有一个 XML 模板文件,其中包含一些模板标记,格式为 {{VARIABLE_NAME}},并且希望使用文本文件的内容查找/替换该标记的所有出现。

所以想象template.xml 看起来像这样:

<?xml>
<root>
    <description>
        {{DESCRIPTION}}
    </description>
</root>

我有一个名为description.txt 的文本文件,它可能包含任何字符(为简单起见,我们假设它已经是 xml 安全的)。我想用文件的内容替换标记,支持换行符和其他字符。

以前我一直在这样的代码中执行此操作(这对简单的字符串很有用):

sed -i '' -e "s/{{DESCRIPTION}}/$DESCRIPTION/g" template.xml

但是,如果 $DESCRIPTION 包含换行符,sed 会拒绝:

sed: 1: "s/{{DESCRIPTION}}/Hello w ...": unescaped newline inside substitute pattern

有没有更好的方法来做到这一点,或者我应该首先搜索/替换 $DESCRIPTION 变量中的所有换行符。还有其他我需要转义的字符吗,比如/

【问题讨论】:

    标签: bash sed


    【解决方案1】:

    这是一个用于替换的 BASH(实际上是 sh)脚本:

    #!/bin/sh
    while IFS= read -r line
    do
        case "$line" in
            *{{DESCRIPTION}})
                cat "description.txt"
                ;;
            *)
                echo "$line"
                ;;
        esac
    done <"template.xml"
    

    在问题陈述中,“{{DESCRIPTION}}”单独出现在一行中。如果一般情况并非如此,则需要进行一些小的更改以保留线路上的其他数据。

    【讨论】:

      【解决方案2】:

      感谢您的回答。总是对学习在 Bash 中做事的新方法感兴趣。然而,我最终以不同的方式解决了它,通过使用我刚刚发现的 Bash 的内置替换表示法转义字符串(sed 失败,原因我仍然不太清楚):

      DESCRIPTION=`cat description.txt`
      DESCRIPTION=${DESCRIPTION//$'\n'/\\$'\n'} # escape newlines
      DESCRIPTION=${DESCRIPTION//\//\\\/} # escape slashes
      DESCRIPTION=${INPUT//$'&'/\\$'&'amp;} # escape ampersands
      # other xml-escaping...
      

      ...然后使用sed 在 output.xml 中实际进行替换内联:

      cp -f template.xml output.xml
      sed -i '' -e "s/{{DESCRIPTION}}/$DESCRIPTION/g" output.xml
      

      由于换行符和斜杠现在被转义了(我错过了什么吗??),sed 命令毫无怨言地接受替换字符串,并且完美地呈现输出文件。

      【讨论】:

        【解决方案3】:

        使用 awk:

        awk -v RS='\0' 'NR==FNR{r=$0;next}{sub(/\{\{DESCRIPTION\}\}/,r)}7' desc temp.xml
        

        我想你知道如何使用重定向来将输出保存到文件中。

        测试:在示例中,文件f 包含许多“特殊”字符

        kent$  cat f.xml
        <?xml>
        <root>
            <description>
                {{DESCRIPTION}}
            </description>
        </root>
        
        kent$  cat f
        foo
        '
        "
        O"'
        /
        \
        
        
        
                - 
        bar
        
        kent$  awk -v RS='\0' 'NR==FNR{r=$0;next}{sub(/\{\{DESCRIPTION\}\}/,r)}7' f f.xml
        <?xml>
        <root>
            <description>
                foo
        '
        "
        O"'
        /
        \
        
        
        
                - 
        bar
        
            </description>
        </root>
        

        【讨论】:

        • 这几乎可以正常工作,但由于某种原因,它只获取文件的最后一行并忽略最后一行之前的任何内容。可能是我的错,我不知道 awk。
        • @chaiguy 是你的 awk gnu 吗?
        • 我运行的是 Mac OS X 10.9,所以可能不是。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-30
        • 2020-09-07
        • 2012-06-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多