对bash中文本文件中的段落进行排序



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

请注意,此解决方案不会在段落之间保留超过一条换行符。

相关内容

  • 没有找到相关文章