如何在 bash 脚本中用多行/流替换单个流/行?

Posted

技术标签:

【中文标题】如何在 bash 脚本中用多行/流替换单个流/行?【英文标题】:How to replace a single stream/line with multiple line/stream in bash scripting? 【发布时间】:2021-11-11 23:07:01 【问题描述】:

我对此很陌生,所以请多多包涵。 :( 在 android 的 bash 脚本中,我试图用存储在另一个 xml 文件中的另一组流/行替换单个 fonts.xml 流,该行是:


    <family name="sans-serif">

而我要替换的是:(存储在另一个 xml 文件中)


    <family name="sans-serif">
        <font weight="100" style="normal">Thin.ttf</font>
        <font weight="100" style="italic">ThinItalic.ttf</font>
        <font weight="300" style="normal">Light.ttf</font>
        <font weight="300" style="italic">LightItalic.ttf</font>
        <font weight="400" style="normal">Regular.ttf</font>
        <font weight="400" style="italic">Italic.ttf</font>
        <font weight="500" style="normal">Medium.ttf</font>
        <font weight="500" style="italic">MediumItalic.ttf</font>
        <font weight="700" style="normal">Bold.ttf</font>
        <font weight="700" style="italic">BoldItalic.ttf</font>
        <font weight="900" style="normal">Black.ttf</font>
        <font weight="900" style="italic">BlackItalic.ttf</font>
    </family>
    <family>

目标是通过 magisk 模块和 Roboto 作为后备使用自定义字体作为默认字体。如何使用 sed 将第一个流替换为预期的流集。我尝试了几种基本的 sed,但似乎都没有用!

【问题讨论】:

sed 是适合这项工作的错误工具。查看 xslt。 【参考方案1】:

如果你真的想为此使用 sed,你可以尝试这个实现,用新行 (\n) 替换未使用的字符 (%),执行替换,然后恢复新行。

#!/bin/bash

multi_line_sed()

    local find_str="$1"
    local replace_str="$2"
    local unused_char="%"

    # 1. substitute out new lines (for stdin and function arguments)
    # 2. perform replacement
    # 3. restore new lines

    find_str=$(printf "$find_str" | tr "\n" "$unused_char")
    replace_str=$(printf "$replace_str" | tr "\n" "$unused_char")

    tr "\n" "$unused_char" |
    sed "s|$find_str|$replace_str|g" |
    tr "$unused_char" "\n"


file="fonts.xml"

find_str="<family name=\"sans-serif\">"
replace_str="$(cat custom_font.xml)"

cat "$file" | multi_line_sed "$find_str" "$replace_str"

【讨论】:

稍作修改即可完美运行。 如果我尝试用第二行代码重复第二组变量作为cat "$file" | multi_line_sed "$find_str2" "$replace_str2" 第一个替换被否决并且只有第二个保留作为最终输出,则会出现另一个问题,如何在一行中使用多个字符串替换? sed 能够使用其标志 sed -i 就地编辑文件,但 tr 不能。您可以先在变量中捕获文件内容,然后在最后将所有内容写回文件。 file_contents=$(cat "$file") printf "$tmp" | multi_line_sed "$find_str" "$replace_str" | multi_line_sed "$find_str2" "$replace_str2" &gt; fonts.xml 我没想到,我想这就是菜鸟应该是的哈哈。我试过multi_line_sed "$find_str" "$replace_str" &amp;&amp; multi_line_sed "$find_str2" "$replace_str2" &gt; fonts.xml'。再次感谢您挽救了这一天。

以上是关于如何在 bash 脚本中用多行/流替换单个流/行?的主要内容,如果未能解决你的问题,请参考以下文章

如何读取多行 fwf 格式,其中行可能流或不流多行

在 bash 脚本中使用 sed 替换多行模式

如何在多行中替换单个字线?

sed多行模板替换

在日志中用主机名替换 IP

Bash将多行字符串转换为单个换行符分隔的字符串[重复]