【问题标题】:How to use sed to search and replace html code strings from awk input variables如何使用 sed 从 awk 输入变量中搜索和替换 html 代码字符串
【发布时间】:2020-01-19 21:19:39
【问题描述】:

我有 6 个 10 列和 19 行的文本文件。每个文本文件的第一行包含一个相同的标题(awk 有意忽略)。出于格式化目的,我将表头作为表头的一部分创建。

示例 - foo1.txt(缩短为前 4 行虚构数据):

H1 H2 H3 H4 H5 H6 H7 H8 H9 H10
1 2 3 4 5 6 7 8 9 10
2 3 4 5 6 7 8 9 10 11
3 4 5 6 7 8 9 10 11 12

包含一些 CSS、表格位置和要替换的表格字符串的模板 html 文件。重要的是不要重写此模板 html 文件,因为它必须在其他情况下多次使用(其他 6 个文本文件集)。表字符串(MYTABLE1、MYTABLE2、...)将需要被 shell 脚本替换。

示例 - template.html:

    <!--some html and css code, followed by below code-->
    <div>
    <div class="wrap">
    <table>
    <caption>foo1</caption>
    <tbody>
    MYTABLE1
    </tbody>
    </table>
    </div>
    <div>
    <div class="wrap">
    <table>
    <caption>foo2</caption>
    <tbody>
    MYTABLE2
    </tbody>
    </table>
    </div>
    <div>
    <div class="wrap">
    <table>
    <caption>foo3</caption>
    <tbody>
    MYTABLE3
    </tbody>
    </table>
    </div>
    <!--then, continues through foo6 and MYTABLE6 and other html code-->

bash 脚本打开每个文本文件,并使用 awk 创建行并从文件中读取以填充标题行下方的每一行。表格 html 包含在来自文本文件的值之间。 awk 的输出存储为变量,然后将其传递给 sed 以在 template.html 文件中搜索 MYTABLE* 字符串,并用包含附加表代码的变量替换它们。然后,sed就是新建一个html文件,以免覆盖template.html文件。脚本的 awk 部分按预期工作,但是 sed 部分抱怨 's/ 并失败。我想这是因为传递了 html 代码?我尝试了多种方法让 sed 接受字符串变量,每次尝试都有 's/ 失败。

示例 - make_table.sh(仅包括要创建的前 3 个表元素):

#!/bin/bash

STRING1=$(cat foo/foo1.txt | awk ' NR==1{next} BEGIN {
print "<tr><th class=\x22right\x22>H1</th>", "<th class=\x22right\x22>H2</th>", "<th>H3</th>", "<th>H4</th>", "<th>H5</th>", "<th>H6</th>", "<th>H7</th>", "<th>H8</th>",  "<th>H9</th>", "<th>H10</th></tr>" }
{ print "<tr><td class=\x22right\x22>" $1 "</td><td class=\x22right\x22>" $2 "</td><td>" $3 "</td><td>" $4 "</td><td>" $5 "</td><td>" $6 "</td><td>" $7 "</td><td>" $8 "</td><td>" $9 "</td><td>" $10 "</td></tr>" }')

STRING2=$(cat foo/foo2.txt | awk ' NR==1{next} BEGIN {
print "<tr><th class=\x22right\x22>H1</th>", "<th class=\x22right\x22>H2</th>", "<th>H3</th>", "<th>H4</th>", "<th>H5</th>", "<th>H6</th>", "<th>H7</th>", "<th>H8</th>",  "<th>H9</th>", "<th>H10</th></tr>" }
{ print "<tr><td class=\x22right\x22>" $1 "</td><td class=\x22right\x22>" $2 "</td><td>" $3 "</td><td>" $4 "</td><td>" $5 "</td><td>" $6 "</td><td>" $7 "</td><td>" $8 "</td><td>" $9 "</td><td>" $10 "</td></tr>" }')

STRING3=$(cat foo/foo3.txt | awk ' NR==1{next} BEGIN {
print "<tr><th class=\x22right\x22>H1</th>", "<th class=\x22right\x22>H2</th>", "<th>H3</th>", "<th>H4</th>", "<th>H5</th>", "<th>H6</th>", "<th>H7</th>", "<th>H8</th>",  "<th>H9</th>", "<th>H10</th></tr>" }
{ print "<tr><td class=\x22right\x22>" $1 "</td><td class=\x22right\x22>" $2 "</td><td>" $3 "</td><td>" $4 "</td><td>" $5 "</td><td>" $6 "</td><td>" $7 "</td><td>" $8 "</td><td>" $9 "</td><td>" $10 "</td></tr>" }')

echo $STRING1
#everything above works as intended

#I've tried (with no luck):
#sed -e 's/MYTABLE1/'${STRING1}'/' \
#sed -e 'c/MYTABLE1/'"$(echo ${STRING1})"'/' \

#below does not work
sed -e 's/MYTABLE1/'"$(echo ${STRING1})"'/' \
    -e 's/MYTABLE2/'"$(echo ${STRING2})"'/' \
    -e 's/MYTABLE3/'"$(echo ${STRING3})"'/' \
    < template.html > template_new.html

如何让 sed 接受这些 STRING* 命令?这可以在纯 awk 中完成吗(不确定 awk 是否可以读取 template.html 并将输出写入 template_new.html)。我真的很想避免使用纯 sed 解决方案,因为除了简单的字符串替换之外,sed 格式没有任何意义。我可以更好地优化 awk 代码吗?

【问题讨论】:

  • 不要将catsedawk一起使用,它们可以直接读取文件:STRING3=$( awk '{some awk code}' foo/foo3.txt)

标签: bash awk sed


【解决方案1】:

解决方案是使用我所拥有的,并且只将分隔符更改为正斜杠以外的其他内容。以下作品:

sed -e 's#MYTABLE1#'"$(echo ${STRING1}"'#'  \
    -e 's#MYTABLE2#'"$(echo ${STRING2}"'#'  \
    -e 's#MYTABLE3#'"$(echo ${STRING3}"'#'  \
    < template.html > template_new.html

【讨论】:

    【解决方案2】:

    如果您在创建模板时知道数据文件的文件名(在您的示例中看起来就像您所做的那样),您可以使用一个 awk 进程完成整个工作(并且安全)。假设模板包含像MYTABLE foo1.txt 这样的行,这些行将被替换为保持不变的所有其他内容——并使用一些变量来使代码更短、更清晰:

    awk <template >new '
    BEGIN{ a="<tr>"; b="<th class=\x22right\x22>"; c="<th>"; d="</th>"; e="</tr>";
      h=a b "H1" d b "H2" d c "H3" d c "H4" d c "H5" d c "H6" d c "H7" d c "H8" d c "H9" d c "H10" d e;
      b="<td class=\x22right\x22>"; c="<td>"; d="</td>" }
    $1=="MYTABLE" { f=$2; getline <f; print h; 
      while((getline <f)>0){ print a b $1 d b $2 d c $3 d c $4 d c $4 d c $4 d c $5 d c $6 d c $7 d c $8 d c $9 d c $10 d e };
      close(f); next }
    { print }'
    
    # the close(f) is only required if you have too many files for awk to open concurrently,
    # but good practice always
    

    另请注意,可以将 awk 的脚本放在带有 -f 的文件中,而不是放在命令行中,但两种方式的功能都是相同的。

    【讨论】:

      【解决方案3】:

      这是因为您的字符串包含终止s 命令的/ 字符。但是,您不必使用/ 字符来分隔s 命令,sed 将接受s 后面的任何内容。尝试改用#

      sed -e "s#MYTABLE1#${STRING1}#"  \
          -e "s#MYTABLE2#${STRING2}#"  \
          -e "s#MYTABLE3#${STRING3}#"  \
          < template.html > template_new.html
      

      请注意,我还减少了引用并删除了不需要的 echo 命令。

      根据 POSIX 规范,您可以使用任何字符作为s 命令的分隔符,而不是反斜杠或换行符。尽管 GNU sed 甚至也会接受反斜杠。见:What delimiters can you use in sed?

      【讨论】:

      • 这仍然不适用于我尝试的磅或其他分隔符。它具有相同的“未终止的 s' 命令”错误。
      • @user2030765,你怎么能这么说并在下面发布答案说改变分隔符是解决方案?您的答案在命令替换中缺少右括号),也许这就是它不起作用的原因......?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-01
      • 2018-12-05
      • 2017-02-08
      • 1970-01-01
      • 2015-01-13
      • 1970-01-01
      相关资源
      最近更新 更多