从文件中删除额外的标题行,除了第一行

Gai*_*tus 18 text-processing

我有一个看起来像这个玩具示例的文件。我的实际文件有 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 的行。

  • 或者`sed '1!{/ID/d;}'` (4认同)
  • 好的; 或者更具体地说是模式匹配,`sed '2,${/^ID Data1 Data2$/d;}' file`(当然,使用正确数量的列之间的空格) (3认同)

Jef*_*ler 26

header=$(head -n 1 input)
(printf "%s\n" "$header";
 grep -vFxe "$header" input
) > output
Run Code Online (Sandbox Code Playgroud)
  1. 将输入文件中的标题行抓取到一个变量中
  2. 打印标题
  3. 处理文件grep以省略与标题匹配的行
  4. 将以上两步的输出捕获到输出文件中

  • @JeffSchaller,_最近_ 和 12 年前一样。在此之前,`head -1` 已经过时了几十年。 (3认同)
  • 或者可能`{ IFS= read -r head; printf '%s\n' "$head"; grep -vF "$head" ; } <文件` (2认同)

Cos*_*tas 10

对于那些不喜欢大括号的人

sed -e '1n' -e '/^ID/d'
Run Code Online (Sandbox Code Playgroud)
  • n表示pass行号1
  • d 删除以开头的所有匹配行 ^ID

  • 这也可以缩短为 `sed '1n;/^ID/d'` 文件名。只是一个建议 (5认同)

Wil*_*ard 6

这是一个有趣的。您可以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)


ter*_*don 6

这里有几个不需要您提前知道第一行的选择:

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,因此可以确保第一行也将被打印。