sort
实用程序使您可以方便地对文件中的行进行排序。然而,有没有一种优雅的方法可以在bash中对空行分隔的段落进行排序?
例如
ccc
aa
aba
bbb
aba
ccc
aaa
必须成为
aaa
aba
bbb
aba
ccc
ccc
aa
一种解决方案似乎是在所有非空白行上替换新的行符号:
cccnaa
abanbbb
abanccc
aaa
然后调用运行sort
aaa
abanbbb
abanccc
cccnaa
然后恢复新线路:
aaa
aba
bbb
aba
ccc
ccc
aa
Perl来拯救;
perl -n00 -e 'push @a, $_; END { print sort @a }' file
-00
选项可启用"段落模式",将输入拆分为空行。
如果与您的示例一样,最后一行输入不一定是空的,则需要单独添加一行换行符。
perl -n00 -e 'push @a, $_;
END { $a[-1] .= "n" if $a[-1] !~ /nn$/;
print sort @a }' file
将空字节放在空行上(在开头再放一个),使用sort -z
,然后删除空字节。您在开始时会得到一个额外的换行符,您可以使用tail
来消除它。
使用echo
+sed
:
(echo ' '; cat myfile) |
sed 's/^$/x0/' |
sort -z |
tr -d ' 00' |
tail -n+2
或者,使用awk
:
awk 'BEGIN{print " "}
/^$/{printf " "} {print $0}' myfile |
sort -z |
tr -d ' 00' |
tail -n+2
也许它并不完美,但它适用于您的输入。
#!/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}"
我会使用不可打印的字符作为分隔符。比方说1
。
您可以使用awk
翻译文件,然后对其进行排序,然后使用awk
将其翻译回:
awk '{$1=$1}1' RS='' OFS='1' file
| sort -i
| awk '{$1=$1}1' FS='1' OFS='n' ORS='nn'
$1=$1
是一个非操作,但它仍然告诉awk使用OFS和/或ORS分隔符重新组装记录。所有的逻辑都是用分隔符来表示的:
第一个awk命令:
RS=''
是记录分隔符的一个特殊值。如果RS
是一个空字符串,那么它默认为两行或更多的后续新行,这实际上是按段落分割的。在这种情况下,字段由新行分隔- CCD_ 15在输出中通过CCD_。输出记录分隔符默认为一个换行符
这给了我们:
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='nn'
将输出记录分隔符设置为两个换行符,这实际上是一个空行
输出:
aaa
aba
bbb
aba
ccc
ccc
aa
请注意,此解决方案不会在段落之间保留超过一条换行符。