在字符最后一次出现后按数字排序文件名

时间:2012-11-30 12:43:45

标签: bash shell

我希望在s最后一次出现之后按数字对文件名进行排序,怎么做?

例如:

01002M00T1relaxouspios1001a001.nii
01002M00T1relaxos301a001.nii
01002M00T1relaxos201a001.nii
01002M00T1relaxouspios901a001.nii

排序的文件名应为:

01002M00T1relaxos201a001.nii
01002M00T1relaxos301a001.nii
01002M00T1relaxouspios901a001.nii
01002M00T1relaxouspios1001a001.nii

我尝试使用

$sort -ts -nk2,4

但它仅适用于前2个文件名。

示例2:

01002M00T1relaxos201a001.nii 
01002M00T1relaxouspios1001a001.nii 
01002M00T130relaxos301a001.nii 
01002M00T130relaxouspios901a001.ni

预期产出:

01002M00T1relaxos201a001.nii 
01002M00T130relaxos301a001.nii 
01002M00T130relaxouspios901a001.ni
01002M00T1relaxouspios1001a001.nii 

3 个答案:

答案 0 :(得分:2)

简单,使用-V选项进行版本排序:

$ sort -V file

01002M00T1relaxos201a001.nii
01002M00T1relaxos301a001.nii
01002M00T1relaxouspios901a001.nii
01002M00T1relaxouspios1001a001.nii

编辑第二个示例后编辑。

一般案例:

$ ls | awk -Fs '{print $NF, $0}' | sort -n | awk '{print $2}'

01002M00T1relaxos201a001.nii
01002M00T130relaxos301a001.nii
01002M00T130relaxouspios901a001.ni
01002M00T1relaxouspios1001a001.nii

答案 1 :(得分:2)

你可以使用像Perl或Python这样的编程语言,它可以让你更多地指定你想要排序的东西,但是如果你坚持使用BASH,你将不得不采用一个小技巧:

您可以使用sed创建排序键,根据您创建的排序键进行排序,然后使用`sed:

删除该键
ls | sed 's/\(.*s\)\(.*\)/\1\2 ^ \2)

以上使用正则表达式的贪婪能力来获得你想要的东西。 \(.*s\)会将所有内容与最终小写s匹配。 \(.*\)将匹配s的所有内容。 \1\2匹配\(...\)组中捕获的各个部分。因此,我有两个字符串;第一个是文件名,第二个是排序字符串。输出将如下所示:

$ ls | sed 's/\(.*s\)\(.*\)/\1\2 ^ \2/'
01002M00T1relaxouspios1001a001.nii ^ 1001a001.nii
01002M00T1relaxos301a001.nii ^ 301a001.nii
01002M00T1relaxos201a001.nii ^ 201a001.nii
01002M00T1relaxouspios901a001.nii ^ 901a001.nii

现在,我可以在^

之后对部分进行排序
$ ls | sed 's/\(.*s\)\(.*\)/\1\2 ^ \2/' | sort -t^ -k2.2
01002M00T1relaxouspios1001a001.nii ^ 1001a001.nii
01002M00T1relaxos201a001.nii ^ 201a001.nii
01002M00T1relaxos301a001.nii ^ 301a001.nii
01002M00T1relaxouspios901a001.nii ^ 901a001.nii

现在,我所要做的就是删除那个排序键:

$ ls | sed 's/\(.*s\)\(.*\)/\1\2 ^ \2/' | sort -t^ -k2.2| sed 's/ ^ .*//'
01002M00T1relaxouspios1001a001.nii
01002M00T1relaxos201a001.nii
01002M00T1relaxos301a001.nii
01002M00T1relaxouspios901a001.nii

答案 2 :(得分:2)

如果数字为uniq 并且足以成为索引,则有一个优雅的 bash only 解决方案。 我们的想法是使用bash array但不使用associative

unset sortedlist
declare -a sortedlist
while read filename;do
    [[ $filename =~ s([0-9]+)[a-rt-z][^s]*$ ]] &&
       sortedlist[${BASH_REMATCH[1]}]=$filename
  done < <(ls)
printf "%s\n" "${sortedlist[@]}"
01002M00T1relaxos201a001.nii
01002M00T1relaxos301a001.nii
01002M00T1relaxouspios901a001.nii
01002M00T1relaxouspios1001a001.nii

注意:在数组中,字段按数字顺序排序,因此1001大于901

Nota2:由于[[ ... =~ ... ]]是一个条件,因此只会忽略与正则表达式不匹配的文件名。