有没有办法忽略UNIX排序中的标题行?

Rob*_*iam 92 unix sorting command-line

我有一个固定宽度字段文件,我正在尝试使用UNIX(Cygwin,在我的情况下)排序实用程序排序.

问题是文件顶部有一个两行标题,它被排序到文件的底部(因为每个标题行以冒号开头).

有没有办法告诉排序"将前两行传递给未排序的"或指定将冒号行排序到顶部的排序 - 其余行总是以6位数字开头(这实际上是关键字I如果有帮助的话,我会整理.

例:

:0:12345
:1:6:2:3:8:4:2
010005TSTDOG_FOOD01
500123TSTMY_RADAR00
222334NOTALINEOUT01
477821USASHUTTLES21
325611LVEANOTHERS00
Run Code Online (Sandbox Code Playgroud)

应该排序:

:0:12345
:1:6:2:3:8:4:2
010005TSTDOG_FOOD01
222334NOTALINEOUT01
325611LVEANOTHERS00
477821USASHUTTLES21
500123TSTMY_RADAR00
Run Code Online (Sandbox Code Playgroud)

Bob*_*obS 109

(head -n 2 <file> && tail -n +3 <file> | sort) > newfile
Run Code Online (Sandbox Code Playgroud)

括号创建一个子shell,包装stdout,这样你就可以管它或重定向它,好像它来自一个命令.

  • 有没有办法让这个版本适用于管道输入数据?我试过`tee>(head -n $ header_size)| tail -n + $ header_size | sort`,但是head似乎在`tail | sort`管道之后运行,所以标题最后打印出来.这是确定性还是竞争条件? (3认同)
  • 谢谢; 我接受这个答案,因为它看起来最完整和简洁(而且我明白它在做什么!) - 不过它应该是“head -n 2”:-) (2认同)

Dav*_*ave 54

如果你不介意使用awk,你可以利用awk内置的管道功能

例如.

extract_data | awk 'NR<3{print $0;next}{print $0| "sort -r"}' 
Run Code Online (Sandbox Code Playgroud)

这将逐字打印前两行,并通过其他方式管道sort.

请注意,这具有非常特定的优点,即能够有选择地对管道输入的部分进行排序.建议的所有其他方法只会对可以多次读取的普通文件进行排序.这适用于任何事情.

  • 美丽,awk永远不会让我惊讶.另外,你不需要`$ 0`,`print`就足够了. (3认同)
  • 非常好,它适用于任意管道,不仅文件! (2认同)
  • @SamWatkins [freeseek's](http://stackoverflow.com/users/4339300/freeseek) [answer](http://stackoverflow.com/a/27368739/343388) 不那么难看。 (2认同)

And*_*rea 36

在简单的情况下,sed可以优雅地完成工作:

    your_script | (sed -u 1q; sort)
Run Code Online (Sandbox Code Playgroud)

或等效地,

    cat your_data | (sed -u 1q; sort)
Run Code Online (Sandbox Code Playgroud)

关键在于1q-- 打印第一行(标题)并退出(将其余的输入留给sort)。

对于给出的示例,2q将解决问题。

-u开关(无缓冲)所需的那些sedS(值得注意的是,GNU的),否则将读取输入的数据块,从而消耗数据要经过sort代替。

  • 在我看来,这是最简单的解决方案,也是最容易记住的。它适用于管道数据,没有特殊考虑或尴尬的引用和转义,并且如果您通过带有 -s 标志的管道排序命令链对多个列进行排序,则不需要多次使用。例如。`bgzip -dc somefile.tsv.gz | (sed -u 2q;排序-k 3,3 -n | 排序-k 2,2 -n -s | 排序-k 1,1 -s) | bgzip -c &gt; my_sorted_file.tsv.gz`。但关键是添加了“-u”标志的编辑,这应该已经解决了上面@RobGilliam 的问题。 (3认同)
  • 您能解释一下管道和括号的工作原理吗? (2认同)

小智 29

这是一个适用于管道数据的版本:

(read -r; printf "%s\n" "$REPLY"; sort)
Run Code Online (Sandbox Code Playgroud)

如果您的标题有多行:

(for i in $(seq $HEADER_ROWS); do read -r; printf "%s\n" "$REPLY"; done; sort)
Run Code Online (Sandbox Code Playgroud)

这个解决方案来自这里

  • 不错.对于单头案例,我使用`extract_data | (读h; echo"$ h";排序)`它足够短,可以记住.您的示例涵盖了更多边缘情况.:)这是最好的答案.在管道上工作.没有awk. (7认同)
  • 在我看来,这应该是公认的答案.简单,简洁,更灵活,因为它也适用于管道数据. (6认同)
  • 好吧,我对此进行了跟踪,看来 bash 不遗余力地做到了这一点。一般来说,如果您用 C 或其他语言对其进行编码,它将无法工作,因为 stdio 会读取的不仅仅是第一个标题行。如果您在可查找文件上运行它,bash 会读取更大的块(在我的测试中为 128 字节),然后 lseeks 返回到第一行末尾之后。如果在管道上运行它,bash 一次读取一个字符,直到它通过行尾。 (2认同)

Ant*_*nko 6

您可以使用tail -n +3 <file> | sort ...(tail将从第3行输出文件内容).

  • 但这会丢失标头,这是不希望的。 (3认同)

Vij*_*jay 5

head -2 <your_file> && nawk 'NR>2' <your_file> | sort
Run Code Online (Sandbox Code Playgroud)

例子:

> cat temp
10
8
1
2
3
4
5
> head -2 temp && nawk 'NR>2' temp | sort -r
10
8
5
4
3
2
1
Run Code Online (Sandbox Code Playgroud)