在bash中,如何对包括数字的字符串进行排序?

时间:2017-01-26 10:59:45

标签: linux bash sorting

我有一个输出文件路径的脚本(通过find):

/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3-something16
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something1
/foo/bar/example/foo/bar/example/foo-bar-example/1.2-something5
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something2
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something10

如何在Bash中列出它们,以便它们根据最后的数字以升序数字顺序排列,而不管版本如何(1.2,1.2.3或1.2.3.4)

Ps:something部分最终可以包含短划线。

期望的输出:

/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something1
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something2
/foo/bar/example/foo/bar/example/foo-bar-example/1.2-something5
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something10
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3-something16

我使用了一个临时的哨兵角色来分隔最后的数字,但在我的情况下它有点复杂。

3 个答案:

答案 0 :(得分:4)

在最后提取数字,将其添加到所有行,按数字排序,最后删除该数字:

sed -r 's/(.*)([^0-9])([0-9]+)$/\3\1\2\3/' file | sort -n | sed 's/^[0-9]*//'

输入后,返回:

/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something1
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something2
/foo/bar/example/foo/bar/example/foo-bar-example/1.2-something5
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something10
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3-something16

我认为这是Schwartzian transform

分段:

$ sed -r 's/(.*)([^0-9])([0-9]+)$/\3\1\2\3/' a
16/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3-something16
1/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something1
5/foo/bar/example/foo/bar/example/foo-bar-example/1.2-something5
2/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something2
10/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something10
#^
#note the numbers here

$ sed -r 's/(.*)([^0-9])([0-9]+)$/\3\1\2\3/' a | sort -n 
1/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something1
2/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something2
5/foo/bar/example/foo/bar/example/foo-bar-example/1.2-something5
10/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something10
16/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3-something16
                                                  # ^
                                                  # now it is ordered

$ sed -r 's/(.*)([^0-9])([0-9]+)$/\3\1\2\3/' a | sort -n | sed 's/^[0-9]*//'
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something1
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something2
/foo/bar/example/foo/bar/example/foo-bar-example/1.2-something5
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something10
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3-something16

答案 1 :(得分:3)

您可以使用此sed + sort + awk

sed -E 's/.*[^0-9]([0-9]+)$/\1 &/' file | sort -n | awk '{print $2}'

/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something1
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something2
/foo/bar/example/foo/bar/example/foo-bar-example/1.2-something5
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3.4-something10
/foo/bar/example/foo/bar/example/foo-bar-example/1.2.3-something16

答案 2 :(得分:1)

如果你能确保你永远不会有#'#'您的文件中的字符,您可以尝试:

sed -e 's/something/#/g' filename.txt | sort -t# -k2 -n | sed -e 's/#/something/g'