当替换命令写入文件中时,Sed 仅在文件的偶数行中进行替换

当替换命令写入文件中时,Sed 仅在文件的偶数行中进行替换

我将所有替换命令都放在一个文件(例如 replace.sed)中,并将其与 sed 的 -f 标志一起使用(sed -f replace.sed InputFile)。但现在我遇到了一种情况,我需要仅在给定输入文件的偶数行上应用这些替换规则(即仅在第 2、4、6 行等上应用)。我无法在 replace.sed 文件中放置任何条件语句,因为其他脚本也使用了该文件。

答案1

使用进程替换来sed动态调整文件中的命令:

$ cat replace.sed
s#foo#bar#

$ printf "foo\nfoo\nfoo\nfoo\n" | sed -f replace.sed
bar
bar
bar
bar

$ printf "foo\nfoo\nfoo\nfoo\n" | sed -f <(sed 's#^#2~2#g' replace.sed)
foo
bar
foo
bar

答案2

sed -f <(sed -e 's/.*/2~2{&;}/' replace.sed) InputFile

答案3

其他答案试图告诉您的是使用sed地址形式:first~step

地址

    … 支持以下地址类型:…

    第一的~
      匹配每一个第行以 line 开头第一的例如,“ sed -n 1~2p”将打印输入流中的所有奇数行,地址“ 2~5”将从第二行开始匹配每五行。  第一的可以为零;在这种情况下, sed操作就像等于 . (这是一个扩展。)

显而易见的解决方案是将 中的每个命令放在 之前replace.sed2~2 或者0~2,如果它在您的 版本中有效sed),以使命令在每隔一行上运行,从第二行开始(即,输入流中的所有偶数行,如您所要求的)。但是你说你不能修改replace.sed。好吧,下一步(如其他答案所确定的,但没有解释)是使用 shell 的流程替代功能,其中充当 的输出文件。如果如您的问题所暗示的那样, 只是一系列简单的替代命令,那么 <(command_list)command_listreplace.sed

sed -f <(sed 's/^/2~2/g' replace.sed)

应该管用。

但这也有缺点:

  • 如果每行有多个命令,则上述操作只会影响每行的第一个命令。
  • 如果您有带有数字地址的命令(例如42s/Zaphod/Beeblebrox/),它们将被转换为,2~242…结果显而易见。
  • 如果您有带有非数字地址的命令(例如/windows/s/command/cmd/),上述操作将直接失败。

如果出现上述任何一种情况,您应使用

sed -f <(sed -e 's/.*/2~2{&;}/' replace.sed)

sed每行上的所有命令放入一个命令组中。

replace.sed但如果有多行命令,这也会失败。

基于上述想法,我想出了

sed -f <(echo '0~2{'; cat replace.sed; echo '}')

这使得全部的 replace.sedreplace.sed文件放入命令组中。在我的初步测试中,这似乎解决了我对其他解决方案提出的问题。如果它在处理非常长的或非常复杂的命令时出现问题,我不会感到惊讶。

相关内容