我在下面有一行SED,这是我每月运行的批处理命令。它是由我之前的某人编写的,我希望了解此代码的各个部分。从两个输出中我可以看出,当顺序行重复时,它需要一行并删除另一行,我只是不明白它是如何用这一行完成的。
sed "$!N; /^\(.*\)\n\1$/!P; D" finalish.txt > final.txt
- Finalish.txt
的例子201408
201409
201409
201409
201409
示例 - Final.txt
201408
201409
答案 0 :(得分:2)
不进入sed
的基础知识,这是您的sed
命令已经细分:
$!N
:如果它不是文件结尾,请将下一行追加到模式空间。这两行将用换行符分隔(\n
)。此时您的模式空间为201408\n201409
。 /^\(.*\)\n\1$/!P
:如果模式空间不包含由换行符\n
)分隔的两个相似内容,那么P
会转到第一个换行符(\n
)。所以这会将201408
打印到STDOUT。但是在第二次迭代期间,模式空间将具有201409\n201409
,并且由于失败正则表达式,所以没有任何内容被打印,我们继续执行下一个命令。D
:D
选择第一个换行符(\n
)并重复sed
脚本。请记住,在重复循环期间,您的模式空间仍然具有201409
因此,在第一次迭代中,201408
被打印但201409
在到达文件末尾之前不会被打印,这时你的正则表达式将再次变为真,并且内容将被打印。
如果您继承了很多sed
代码,我强烈推荐使用python
编写的sedsed实用程序,它将帮助您理解错综复杂的sed
经常成为维护的噩梦。
以下是从sedsed
实用程序运行的示例(我没有显示所有迭代,因为它非常详细,但是你得到了图片。我对输出的真正意义添加了一些注释。另请注意我我使用单引号,因为我在Mac(BSD Unix)而不是Windows):
$ sedsed.py -d '$!N; /^\(.*\)\n\1$/!P; D' file
PATT:201408$ # This shows your current pattern space
HOLD:$ # This shows your current hold buffer
COMM:$ !N # This shows the command that is going to run
PATT:201408$ # This shows the pattern space after the command has ran
201409$
HOLD:$ # This shows the hold buffer after the command has ran
COMM:/^\(.*\)\n\1$/ !P # This shows the command being ran
201408 # Anything without a <TAG:> is what gets printed to STDOUT
PATT:201408$
201409$
HOLD:$
COMM:D
PATT:201409$
HOLD:$
...
...
...
COMM:$ !N
PATT:201409$
HOLD:$
COMM:/^\(.*\)\n\1$/ !P
201409
PATT:201409$
HOLD:$
COMM:D
我还建议,一旦您了解了sed
命令的编写内容,就可以将它们移植到更友好的脚本语言,如awk
,perl
或{{ 1}}
答案 1 :(得分:0)
这不会帮助您理解sed
,但这里只有awk
才能获得唯一的行。
awk '!seen[$0]++' finalish.txt
201408
201409