从bash

时间:2016-06-07 01:26:58

标签: bash sorting

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    

4 个答案:

答案 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