对bash中的文本文件中的段落进行排序
问题描述:
sort
实用程序让我们可以方便地对文件中的行进行排序。但是,有没有一种优雅的方式来排序在bash中空行分隔的段落?对bash中的文本文件中的段落进行排序
例如
ccc
aa
aba
bbb
aba
ccc
aaa
将不得不成为
aaa
aba
bbb
aba
ccc
ccc
aa
一种解决方案似乎是所有非空行更换新线符号:
ccc\naa
aba\nbbb
aba\nccc
aaa
然后调用运行sort
aaa
aba\nbbb
aba\nccc
ccc\naa
,然后恢复新线:
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] !~ /\n\n$/;
print sort @a }' file
答
可能是它并不完美,但它的工作对你的输入。
#!/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='\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'
将输出记录分隔符设置为两个换行符,这实际上是一个空格y线。
输出:
aaa
aba
bbb
aba
ccc
ccc
aa
注意,该解决方案将不会保留超过段落之间的单个新行了。
你能澄清一下为什么你可以使用'sort'工具,而不是'sed'工具吗?我真的没有看到这种区别。你还可以使用哪些其他工具,而不是用于? – ruakh
另外 - 您的系统的“排序”支持使用\ 0而不是\ n作为分隔符吗? – ruakh
@ruakh我将编辑该问题。如果你有一个'sed'解决方案,我确实很好。 – john1234