如何在Bash中使用多行排序?

9

我正在尝试对一个包含名字和其他字符串的列表进行排序,例如:

John Doe
AVAIL

Sara Doe
CALL

Jim Doe
AVAIL

我正在尝试按名称对它们进行排序,但是使用sort似乎无法弄清楚。是否有人可以提供一些指导?

我的最终输出应该如下所示:

Jim Doe
AVAIL

John Doe
AVAIL

Sara Doe
CALL

非常感谢!

有趣的是,从你的例子中并不清楚你是按照第一行还是第二行进行排序的 ;) - Jonas Schäfer
对不起,实际上我想按字母顺序对第一行进行排序。 - Tristan Lanford
3个回答

10

可能远非最佳,但是

sed -r ':r;/(^|\n)$/!{$!{N;br}};s/\n/\v/g' names | sort | sed 's/\v/\n/g'

看起来可以完成任务(names是记录文件)。这允许任意长度的记录,而不仅仅是2行。


1
@lev 对于那些不太“流利”于 sed 的人,你能简要叙述一下表达式的前半部分吗?你的基本方法是消除换行符(将 \v 放在其位置),对长行进行排序,然后用 \n 替换 \v 吗? - Levon
@Levon 你说得完全正确 :) 它会读取所有内容直到空行(一个记录),然后将其中的换行符更改为\v。现在所有记录都在单行上。它们被排序,然后\v被转换回\n - Lev Levitsky
1
+1 @LevLevitsky 很好,谢谢。我正在使用SO学习许多新东西 :-) .. 另外其他人也可能在某个时候遇到这个问题。感谢您的回复/解释。 - Levon
只是一个快速的问题,稍微改变一下这个逻辑。当你需要按照字符序列"---"而不是空行来分隔记录时,你会如何改变它? - martinnovoty
1
@martinnovoty 相同的序列可以出现在记录内吗?如果不行,那就更容易了:将所有换行符改为\v,然后将 --- 改为换行符,然后排序,再将\v改为\n - Lev Levitsky

0

虽然不能直接实现,但你可以使用一些中间形式来达到目的。我假设你的值(CALL、AVAIL等)是有限的。否则,你需要使用更复杂的模式,但这也是可以实现的。实际上,在Bash中任何事情都可以做到 :-)

cat sorting | sed -n '1h; 1!H; ${ g; s/\nCALL\n/::CALL::/g; s/\nAVAIL\n/::AVAIL::/g ; s/\nAVAIL/::AVAIL::/g p }' | sort | sed "s/::/\n/g"
Jim Doe
AVAIL

John Doe
AVAIL

Sara Doe
CALL

0

不确定它是否适用于您,但有一些限制,这是一行代码,可以实现您需要的功能。

awk '{if ((NR%2-1)==0) {line=sprintf("%-30s",$0)} else {print line ":" $0}}' | \
  sort --key=1,30 | tr ':' '\n'

假设:记录之间没有空行,名称始终少于30个字符,并且文本中没有使用:

如果假设不同,我相信你可以想出如何进行更改。

简而言之,它使用“:”作为分隔符合并两行,将第一行填充到30个字符并使用前30个字符进行排序。然后再将行拆分回来。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接