Bash 按数字 AND 字长 AND 字母顺序排序
Bash sort by number AND word length AND alphabetically
我的数组中有这些字符串:
3 rere 33.33%
2 ena 22.22%
1 something 11.11%
1 som 11.11%
1 ok 11.11%
1 evo 11.11%
预期结果是:
3 rere 33.33%
2 ena 22.22%
1 something 11.11%
1 evo 11.11%
1 som 11.11%
1 ok 11.11%
它们按数字降序排列。
我也想按中间单词的长度排序,但如果单词长度相同,则按字母顺序排序。
这些不是专栏。
我想把它分成两个数组然后排序,但是如何将它们连接在一起?
有人有想法吗?
Perl 来拯救!
perl -l -0777 -aF'\n' -ne '
print for map join(" ", @$_),
sort { $b->[0] <=> $a->[0]
|| length($a->[1]) <=> length($b->[1])
|| $a->[1] cmp $b->[1] }
map [ split ],
@F;
' input-file
-n
逐条读取输入记录
-0777
将整个文件设置为一条记录
-l
在打印中添加换行符
-a
拆分输入
-F'\n'
告诉 -a
在换行符上拆分
- 每行然后按 split 空格分割,按第 0 列的数字 (
<=>
) 排序,或按第一列的长度排序,或按字母顺序排序 (cmp
)按第一列
您不能使用 sort
按长度排序。让我们试试 Schwartzian transform:
awk '{print length(), [=10=]}' file | sort -k2,2nr -k1,1nr -k3,3 | cut -d" " -f2-
awk 命令接受 1 something 11.11%
并输出 9 1 something 11.11%
。
Then sort 首先按第 2 个字段的数值排序,然后按第 1 个字段的数值排序,然后按第 3 个字段的词法排序。
然后 cut 删除第一个字段。
这背后的想法与Schwartzian transform used in 非常相似:我们添加一个排序字段(在本例中是第二列的长度),用它来排序,然后再次删除它:
while read -r col1 word rest; do
printf "%d\t%s %s %s\n" "${#word}" "$col1" "$word" "$rest"
done < infile | sort -k 2,2nr -k 1,1nr -k 3,3 | cut -f 2
这导致
3 rere 33.33%
2 ena 22.22%
1 something 11.11%
1 evo 11.11%
1 som 11.11%
1 ok 11.11%
while 循环后,输出如下所示:
4 3 rere 33.33%
3 2 ena 22.22%
9 1 something 11.11%
3 1 som 11.11%
2 1 ok 11.11%
3 1 evo 11.11%
第二列中有一个新列,其中包含字符串的长度。它是制表符分隔的,以便以后更容易 cut
。
对于 sort
,我们使用 -k
参数指定用于排序的内容(sort
不关心字段是制表符还是 space 分隔) : 2,2nr
仅使用第二个字段,按数字和降序排列; 1,1nr
也是如此,3,3
只是您的标准词法排序。
输出现在看起来像这样:
4 3 rere 33.33%
3 2 ena 22.22%
9 1 something 11.11%
3 1 evo 11.11%
3 1 som 11.11%
2 1 ok 11.11%
现在我们只需去掉第一列,为此我们使用 cut
并利用 printf
引入的制表符分隔。
Bash while 循环非常慢,Perl 解决方案可能快几个数量级。
我的数组中有这些字符串:
3 rere 33.33%
2 ena 22.22%
1 something 11.11%
1 som 11.11%
1 ok 11.11%
1 evo 11.11%
预期结果是:
3 rere 33.33%
2 ena 22.22%
1 something 11.11%
1 evo 11.11%
1 som 11.11%
1 ok 11.11%
它们按数字降序排列。
我也想按中间单词的长度排序,但如果单词长度相同,则按字母顺序排序。
这些不是专栏。
我想把它分成两个数组然后排序,但是如何将它们连接在一起? 有人有想法吗?
Perl 来拯救!
perl -l -0777 -aF'\n' -ne '
print for map join(" ", @$_),
sort { $b->[0] <=> $a->[0]
|| length($a->[1]) <=> length($b->[1])
|| $a->[1] cmp $b->[1] }
map [ split ],
@F;
' input-file
-n
逐条读取输入记录-0777
将整个文件设置为一条记录-l
在打印中添加换行符-a
拆分输入-F'\n'
告诉-a
在换行符上拆分- 每行然后按 split 空格分割,按第 0 列的数字 (
<=>
) 排序,或按第一列的长度排序,或按字母顺序排序 (cmp
)按第一列
您不能使用 sort
按长度排序。让我们试试 Schwartzian transform:
awk '{print length(), [=10=]}' file | sort -k2,2nr -k1,1nr -k3,3 | cut -d" " -f2-
awk 命令接受 1 something 11.11%
并输出 9 1 something 11.11%
。
Then sort 首先按第 2 个字段的数值排序,然后按第 1 个字段的数值排序,然后按第 3 个字段的词法排序。
然后 cut 删除第一个字段。
这背后的想法与Schwartzian transform used in
while read -r col1 word rest; do
printf "%d\t%s %s %s\n" "${#word}" "$col1" "$word" "$rest"
done < infile | sort -k 2,2nr -k 1,1nr -k 3,3 | cut -f 2
这导致
3 rere 33.33%
2 ena 22.22%
1 something 11.11%
1 evo 11.11%
1 som 11.11%
1 ok 11.11%
while 循环后,输出如下所示:
4 3 rere 33.33%
3 2 ena 22.22%
9 1 something 11.11%
3 1 som 11.11%
2 1 ok 11.11%
3 1 evo 11.11%
第二列中有一个新列,其中包含字符串的长度。它是制表符分隔的,以便以后更容易 cut
。
对于 sort
,我们使用 -k
参数指定用于排序的内容(sort
不关心字段是制表符还是 space 分隔) : 2,2nr
仅使用第二个字段,按数字和降序排列; 1,1nr
也是如此,3,3
只是您的标准词法排序。
输出现在看起来像这样:
4 3 rere 33.33%
3 2 ena 22.22%
9 1 something 11.11%
3 1 evo 11.11%
3 1 som 11.11%
2 1 ok 11.11%
现在我们只需去掉第一列,为此我们使用 cut
并利用 printf
引入的制表符分隔。
Bash while 循环非常慢,Perl 解决方案可能快几个数量级。