sort
实用程序可让您方便地对文件中的行进行排序。但是,有没有一种优雅的方法来在bash中对空行分隔的段落进行排序?
例如
ccc
aa
aba
bbb
aba
ccc
aaa
必须成为
aaa
aba
bbb
aba
ccc
ccc
aa
一种解决方案似乎是在所有非空白行上替换新的行符号:
ccc\naa
aba\nbbb
aba\nccc
aaa
然后调用run sort
aaa
aba\nbbb
aba\nccc
ccc\naa
然后恢复新行:
aaa
aba
bbb
aba
ccc
ccc
aa
答案 0 :(得分:4)
Perl救援;
perl -n00 -e 'push @a, $_; END { print sort @a }' file
-00
选项启用"段落模式"它将输入分成空行。
如果 - 如您的样本中 - 最后一个输入行不一定是空的,则需要单独添加换行符。
perl -n00 -e 'push @a, $_;
END { $a[-1] .= "\n" if $a[-1] !~ /\n\n$/;
print sort @a }' file
答案 1 :(得分:0)
可能它并不完美,但它对您的投入有用。
#!/bin/bash
par=""
while read line
do
if [ "${#line}" -gt 0 ]; then
read -d '' par <<EOF
$par
$line
EOF
fi
if [ "${#line}" -eq 0 ]; then
sort <<< "$par"
par=""
echo
fi
done < "${1:-/dev/stdin}"
答案 2 :(得分:0)
我会使用不可打印的char作为分隔符号。我们说\1
。
您可以使用awk
翻译文件,然后对其进行排序,然后使用awk
将其翻译回来:
awk '{$1=$1}1' RS='' OFS='\1' file \
| sort -i \
| awk '{$1=$1}1' FS='\1' OFS='\n' ORS='\n\n'
$1=$1
是一个无操作但它仍然告诉awk使用OFS和/或ORS分隔符重新组装记录。所有逻辑都使用分隔符表示:
第一个awk命令:
RS=''
是记录分隔符的特殊值。如果RS
是一个空字符串,则默认为两个或多个后续新行,这些行有效地按段落分割。在这种情况下,字段由新行分隔。OFS='\1'
在输出中按\1
分隔字段。输出记录分隔符默认为一个换行符。这给了我们:
ccc<garbage>aa
aba<garbage>bbb
aba<garbage>ccc
aaa
我们现在sort -i
可以。 -i
忽略不可打印的字符,这给了我们:
aaa
aba<garbage>bbb
aba<garbage>ccc
ccc<garbage>aa
第二个awk命令
FS='\1'
按\1
OFS='\n'
将输出字段分隔符设置为换行符ORS='\n\n'
将输出记录分隔符设置为两个换行符,实际上是一个空行。输出:
aaa
aba
bbb
aba
ccc
ccc
aa
请注意,此解决方案不会在段落之间保留多个换行符。
答案 3 :(得分:0)
将空字节放在空行上(并在开头添加一个空字节),使用sort -z
,然后删除空字节。您一开始会以多余的换行符结尾,可以使用tail
来消除它。
使用echo
+ sed
:
(echo '\0'; cat myfile) |
sed 's/^$/\x0/' |
sort -z |
tr -d '\000' |
tail -n+2
或者,使用awk
:
awk 'BEGIN{print "\0"}
/^$/{printf "\0"} {print $0}' myfile |
sort -z |
tr -d '\000' |
tail -n+2