如何对单行分隔项目进行数字排序?

如何对单行分隔项目进行数字排序?

我有一行(或多行)由任意字符分隔的数字。我可以使用哪些 UNIX 工具对每行的项目进行数字排序,并保留分隔符?

示例包括:

  • 号码列表;输入:10 50 23 42;排序:10 23 42 50
  • IP地址;输入:10.1.200.42;排序:1.10.42.200
  • CSV;输入:1,100,330,42;排序:1,42,100,330
  • 以竖线分隔;输入:400|500|404;排序:400|404|500

由于分隔符是任意的,因此请随意使用您选择的单字符分隔符来提供(或扩展)答案。

答案1

gawkGNU awk) 为了asort()功能:

gawk -v SEP='*' '{ i=0; split($0, arr, SEP); len=asort(arr);
    while ( ++i<=len ){ printf("%s%s", i>1?SEP:"", arr[i]) }; 
        print "" 
}' infile

*将字段分隔符替换SEP='*'为您的分隔符



如果是单行,您还可以使用以下命令(因为最好不要使用 shell 循环进行文本处理

tr '.' '\n' <<<"$aline" | sort -n | paste -sd'.' -

代替 .与你的分隔符。
添加-usort上面的命令以删除重复项。

笔记:
您可能需要使用-g, --general-numeric-sort选项 ofsort而不是-n, --numeric-sort来处理任何类别的数字(整数、浮点数、科学数、十六进制等)。

$ aline='2e-18,6.01e-17,1.4,-4,0xB000,0xB001,23,-3.e+11'
$ tr ',' '\n' <<<"$aline" |sort -g | paste -sd',' -
-3.e+11,-4,2e-18,6.01e-17,1.4,23,0xB000,0xB001

不需要awk改变,它仍然会处理这些。

答案2

使用perl有一个明显的版本;分割数据,排序,然后再次连接起来。

分隔符需要列出两次(一次在 the 中split,一次在 the 中join

例如对于一个,

perl -lpi -e '$_=join(",",sort {$a <=> $b} split(/,/))'

所以

echo 1,100,330,42 | perl -lpi -e '$_=join(",",sort {$a <=> $b} split(/,/))'
1,42,100,330

由于 是split正则表达式,因此该字符可能需要引用:

echo 10.1.200.42 | perl -lpi -e '$_=join(".",sort {$a <=> $b} split(/\./))'
1.10.42.200

通过使用-a-F选项,可以消除分割。使用-p循环,像以前一样并将结果设置为$_,这将自动打印:

perl -F'/\./' -aple '$_=join(".", sort {$a <=> $b} @F)'

答案3

使用Python和类似的想法斯蒂芬·哈里斯的回答:

python3 -c 'import sys; c = sys.argv[1]; sys.stdout.writelines(map(lambda x: c.join(sorted(x.strip().split(c), key=int)) + "\n", sys.stdin))' <delmiter>

所以像这样:

$ cat foo
10.129.3.4
1.1.1.1
4.3.2.1
$ python3 -c 'import sys; c = sys.argv[1]; sys.stdout.writelines(map(lambda x: c.join(sorted(x.strip().split(c), key=int)) + "\n", sys.stdin))' . < foo
3.4.10.129
1.1.1.1
1.2.3.4

遗憾的是,必须手动执行 I/O 使得它远不如 Perl 版本优雅。

答案4

重击脚本:

#!/usr/bin/env bash

join_by(){ local IFS="$1"; shift; echo "$*"; }

IFS="$1" read -r -a tokens_array <<< "$2"
IFS=$'\n' sorted=($(sort -n <<<"${tokens_array[*]}"))
join_by "$1" "${sorted[@]}"

例子:

$ ./sort_delimited_string.sh "." "192.168.0.1"
0.1.168.192

基于

相关内容