sed的'N'命令间歇性地工作

nan*_*ker 2 linux bash sed

这是我要格式化的示例文本块:

<tr><td></td><td>tear a cat in, to make all split.</td><td></td></tr>
<tr><td></td><td class="tdci">The raging rocks</td><td></td></tr>
<tr><td></td><td class="tdci">The foolish Fates.</td></tr>
<tr><td></td><td>This was lofty! Now name the rest of the players.</td><td></td></tr>
Run Code Online (Sandbox Code Playgroud)

在脚本中使用这两个'sed'命令:

sed -ri '/^<tr><td><\/td><td>/N;s/(\n<tr><td><\/td><td class="tdci">)/\n<tr><td>\&nbsp;<\/td><\/tr>\1/' "$f"   #insert table row with empty data fields (blank line) above first line with 'class="tdci"'
sed -ri '/^<tr><td><\/td><td class="tdci">/N;s/(\n<tr><td><\/td><td>)/\n<tr><td>\&nbsp;<\/td><\/tr>\1/' "$f"   #insert table row with empty data fields (blank line) after last line with 'class="tdci"'
Run Code Online (Sandbox Code Playgroud)

这是结果:

<tr><td></td><td>tear a cat in, to make all split.</td><td></td></tr>
<tr><td>&nbsp;</td></tr>
<tr><td></td><td class="tdci">The raging rocks</td><td></td></tr>
<tr><td></td><td class="tdci">The foolish Fates.</td></tr>
<tr><td></td><td>This was lofty! Now name the rest of the players.</td><td></td></tr>
Run Code Online (Sandbox Code Playgroud)

因此第一个sed命令的工作原理是在第一行上方插入一个空白表行class="tdci",但几乎相同的第二个sed命令意味着在最后一行之后插入一个空白表行class="tdci"不起作用.

我通常会保存这些类型的编辑,在多行之间进行编辑,因为我从来没有遇到类似命令的问题,但由于某种原因sed,"我N;s/一直都很喜欢",就像在这个例子中,一个实例工作很好,但是第二个没有.\r在这些命令运行之前,脚本会删除所有前导/尾随空格和任何Winblowz回车符().

由于我有大量要编辑的文件,我当然更愿意让这个在脚本中工作,如果有人能够看到任何明显的我做错了.

额外细节:

对不起,我忘了提到我sed在Linux上运行(Debian stable)

tha*_*guy 5

从小做起!对于您正在做的事情,这是一个更简单的测试用例:

a1
b1
b2
a2
Run Code Online (Sandbox Code Playgroud)

这是您为此测试用例翻译的代码,尝试c1在第一个"b"之前插入并c2在最后一个之后插入:

sed -ri '/a/N; s/(\nb)/\nc1\1/' file
sed -ri '/b/N; s/(\na)/\nc2\1/' file
Run Code Online (Sandbox Code Playgroud)

像你说的那样,第一个命令似乎有效:

a1
c1
b1
b2
a1
Run Code Online (Sandbox Code Playgroud)

第二个没有,只是给你与上面相同的结果而不是插入c2.

以下是您可能认为会发生的事情,粗体部分不正确:

  1. a1 被阅读和打印.
  2. c1 被阅读和打印.
  3. b1 被读了.
    • 它匹配/b/,并b2与之一起阅读N.
    • 它不匹配\na.
    • b1 打印出来
  4. b2是第二次读.
    • 它匹配/b/,并a与之一起阅读N.
    • 它匹配\na.c2附加.
    • b2\nc2\na 打印出来.

这是实际发生的事情,

  1. a1 被阅读和打印.
  2. c1 被阅读和打印.
  3. b1 被读了.
    • 它匹配/b/,并b2与之一起阅读N.
    • 它不匹配\na.
    • b1\nb2 打印出来
  4. a2阅读和打印,因为b2上面已经阅读过.

这是一个有效的命令:

sed -ri '/b/ { :b; N; s/\na/\nc2&/; te; P; D; bb; }; :e;' file
Run Code Online (Sandbox Code Playgroud)

在伪代码中 - 在评论中大致相应的sed部分 - 这是:

if (input.matches("b")) {                               // /b/ {
  while(true) {                                         // :b
    input += "\n" + readline();                         // N
    if(input.matches("\na")) {                          // s/\na/ ..
      input = input.replace("(\na)", "\nc2\1");         // .. \nc2&/
      goto exit;                                        // te
    }
    print(input.substring(0, input.indexOf('\n'));      // P
    input = input.substring(input.indexOf('\n') + 1);   // D
  }                                                     // bb
}                                                       // }
:exit                                                   // :e
Run Code Online (Sandbox Code Playgroud)

翻译回您的数据:

sed -ri '/^<tr><td><\/td><td class="tdci">/ { :b; N; s/(\n<tr><td><\/td><td>)/\n<tr><td>\&nbsp;<\/td><\/tr>\1/; te; P; D; bb; }; :e' "$f"
Run Code Online (Sandbox Code Playgroud)