我有一个看起来像这个玩具示例的文件。我的实际文件有 400 万行,我需要删除其中大约 10 行。
ID Data1 Data2
1 100 100
2 100 200
3 200 100
ID Data1 Data2
4 100 100
ID Data1 Data2
5 200 200
Run Code Online (Sandbox Code Playgroud)
我想删除看起来像标题的行,除了第一行。
最终文件:
ID Data1 Data2
1 100 100
2 100 200
3 200 100
4 100 100
5 200 200
Run Code Online (Sandbox Code Playgroud)
我怎样才能做到这一点?
bkm*_*ney 36
您可以使用
sed '2,${/ID/d;}'
Run Code Online (Sandbox Code Playgroud)
这将从第 2 行开始删除带有 ID 的行。
Jef*_*ler 26
header=$(head -n 1 input)
(printf "%s\n" "$header";
grep -vFxe "$header" input
) > output
Run Code Online (Sandbox Code Playgroud)
grep
以省略与标题匹配的行Cos*_*tas 10
对于那些不喜欢大括号的人
sed -e '1n' -e '/^ID/d'
Run Code Online (Sandbox Code Playgroud)
n
表示pass
行号1
d
删除以开头的所有匹配行 ^ID
这是一个有趣的。您可以sed
直接使用删除第一行的所有副本并将其他所有内容保留在原处(包括第一行本身)。
sed '1{h;n;};G;/^\(.*\)\n\1$/d;s/\n.*$//' input
Run Code Online (Sandbox Code Playgroud)
1{h;n;}
将第一行放入保留空间,打印它,然后读入下一行——跳过sed
第一行的其余命令。(它还跳过1
了第二行的第一个测试,但这并不重要,因为该测试不会应用于第二行。)
G
将换行符后跟保持空间的内容附加到模式空间。
/^\(.*\)\n\1$/d
如果换行符之后的部分(即从保持空间附加的部分)与换行符之前的部分完全匹配,则删除模式空间的内容(从而跳到下一行)。这是重复标题的行将被删除的地方。
s/\n.*$//
删除由G
命令添加的文本部分,以便打印的只是文件中的文本行。
但是,由于正则表达式很昂贵,P
如果换行符后面的部分(即从保持空间中附加的部分)与该部分不完全匹配,则稍微快一点的方法是使用相同的条件(否定)并打印到换行符在换行符之前,然后无条件删除模式空间:
sed '1{h;n;};G;/^\(.*\)\n\1$/!P;d' input
Run Code Online (Sandbox Code Playgroud)
给出您的输入时的输出是:
ID Data1 Data2
1 100 100
2 100 200
3 200 100
4 100 100
5 200 200
Run Code Online (Sandbox Code Playgroud)
这里有几个不需要您提前知道第一行的选择:
perl -ne 'print unless $_ eq $k; $k=$_ if $.==1;
Run Code Online (Sandbox Code Playgroud)
该-n
标志告诉 perl 循环其输入文件,将每一行保存为$_
. 该$k=$_ if $.==1;
节省的第一行($.
是行号,所以$.==1
只能是1号线真)作为$k
。该print unless $k eq $_
打印如果它不是作为一个保存在同一当前行$k
。
或者,同样的事情awk
:
awk '$0!=x;(NR==1){x=$0}' file
Run Code Online (Sandbox Code Playgroud)
在这里,我们测试当前行是否与变量中保存的相同x
。如果测试结果$0!=x
为真(如果当前行$0
与 不同x
),将打印该行,因为 awk 对真表达式的默认操作是打印。第一行 ( NR==1
) 保存为x
. 由于这是在检查当前行是否匹配之后完成的x
,因此可以确保第一行也将被打印。