如何在sed中输入命令的结果作为字符串参数

时间:2016-09-04 13:32:31

标签: linux bash shell sed

我想在我的bash终端上执行如下命令:

sed -i '6i `sed '1!d' input.in`' out

我可以在文件的第6行插入(使用替换-i选项)sed '%1!d' input.in命令的结果。我没有找到任何有用的东西,并尝试过`com`,$(com)和com | sed -i'6i'out,其中com代表sed '%1!d' input.in。我没有任何问题更改整个命令的语法,但我希望它在终端使用sed上写成一行。

感谢收听, 等待你的回答。

对于EdMorton:

Example Input:

input.in:
into a lake.

out:
Mary was runing around a pond and fell
into a lake.


Mary fell into a what?

Desired Output:
Mary was runing around a pond and fell
into a lake.


Mary fell into a what?
into a lake.

2 个答案:

答案 0 :(得分:2)

尝试在标准输入上使用r而不是i

sed '%1!d' input.in |
sed -i '6r /dev/stdin' out

如果您的平台不支持/dev/stdin/dev/fd/0,请查看您的sed是否支持-表示标准输入...或者,在最差的情况下案件,诉诸临时档案。

正如评论者已经指出的那样,%1!d在大多数sed方言中似乎不是一个有效的命令,但这在这里基本上不重要。 (如果您的意思是仅打印第一行,可能您的意思是sed '1!d',尽管sed 'p;q'可以更有效地执行此操作。)

答案 1 :(得分:1)

sed用于单个行上的简单替换,即全部。对于其他任何你应该使用awk。

鉴于此修改后的输入文件

$ cat input.in
a Windows folder C:\Windows\Temp

以下是您在评论中发布的sed解决方案:

$ sed '1!d' input.in > temp.of.in && sed "6i `cat temp.of.in`" out
Mary was runing around a pond and fell
into a lake.


Mary fell into a what?
a Windows folder C:WindowsTemp

这就是awk解决方案在没有临时文件的情况下更高效,更准确地执行的操作:

$ awk 'NR==1{x=$0;nextfile} FNR==6{print x} 1' input.in out
Mary was runing around a pond and fell
into a lake.


Mary fell into a what?
a Windows folder C:\Windows\Temp

注意awk解决方案保留了路径分隔符反斜杠,而sed剥离了它们。另请注意,您应该在sed命令行的末尾添加&& rm temp.of.in来清理临时文件,并且应该使用$(..)来执行命令,而不是过时的反引号。

awk解决方案使用GNU awk用于;nextfile,其他awks用}NR==FNR{next或类似替换它但是因为你使用GNU sed我假设你也有GNU awk。 / p>

请注意,如果您有兴趣使用sed并且接受它并不能完全重现输入,那么有更简单,更有效的方法来执行当前脚本所做的事情,例如:

sed "6i $(head -1 input.in)" out

甚至是你最初的想法,只是为了删除过时的反引号和1!d的否定逻辑而重写:

sed "6i $(sed -n '1p' input.in)" out

但严重 - 只需使用awk。对于除了单独行上的简单替换之外的任何内容,它比sed更加健壮,高效,清晰,可移植,可扩展等等。

编辑要解决您的评论中的问题:

  1. 你能解释一下关于awk的论点。 没有参数,只有一个脚本说:如果这是从第一个文件读取的第一行,将其保存在变量x中,然后转到下一个文件。如果这是第二个文件的第6行打印变量x的内容。对于第二个文件的每一行,打印它(1是惯用的,但乍一看有点棘手 - 它是一个真实条件,因此它调用打印当前输入的默认操作,相当于只写{print}
  2. 如何将out文件替换为输出(不使用'>')作为选项-i在sed上执行并避免将其打印到stdout? Just像GNU sed有-i,GNU awk有-i inplace。但要小心,因为,就像sed一样,它适用于每个输入文件,所以如果你不打印第一个文件的内容,那么当脚本完成后,第一个文件将为空。有各种各样的方法来解决这个问题,包括简单地打印文件1中的行或在BEGINFILE / ENDFILE块中打开/关闭原位编辑,请参阅https://www.gnu.org/software/gawk/manual/gawk.html#Extension-Sample-Inplace,但恕我直言awk 'script' file1 file2 > temp && mv temp file2是最简单的最清晰,也可以移动到所有的awks / seds /无论如何。
  3. 此外,如果存在类似&#34的多线解决方案,请选择第1至4行"来自" input.in"并将它们放在" out"的第6行?没问题:
  4. awk '
        NR==FNR { if (NR<=4) x=x $0 ORS; else nextfile }
        FNR==6 { printf "%s", x }
        { print }
    ' input.in out
    

    为了清楚起见,我将1从上一个脚本更改为{ print }