我想按最后一次出现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
很简单,使用 -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
你可以使用像Perl或Python这样的编程语言,让你更有能力指定你想要排序的内容,但如果你坚持使用BASH,你将不得不使用一个小技巧:
您可以使用 sed
创建排序键,根据您创建的排序键进行排序,然后使用 'sed:
ls | sed 's/(.*s)(.*)/12 ^ 2)
上面利用正则表达式的贪婪力量来得到你想要的东西。(.*s)
会将所有内容与最终的小写s
匹配。(.*)
将匹配s
的一切.1
和2
与(...)
组中捕获的各个部分相匹配。因此,我有两个字符串;第一个是文件名,第二个是排序字符串。输出将如下所示:
$ ls | sed 's/(.*s)(.*)/12 ^ 2/'
01002M00T1relaxouspios1001a001.nii ^ 1001a001.nii
01002M00T1relaxos301a001.nii ^ 301a001.nii
01002M00T1relaxos201a001.nii ^ 201a001.nii
01002M00T1relaxouspios901a001.nii ^ 901a001.nii
现在,我可以在^
之后对部分进行排序:
$ ls | sed 's/(.*s)(.*)/12 ^ 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)(.*)/12 ^ 2/' | sort -t^ -k2.2| sed 's/ ^ .*//'
01002M00T1relaxouspios1001a001.nii
01002M00T1relaxos201a001.nii
01002M00T1relaxos301a001.nii
01002M00T1relaxouspios901a001.nii
如果数字是 uniq 并且足以成为索引,则有一个优雅的 bash 解决方案。这个想法是使用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 "%sn" "${sortedlist[@]}"
01002M00T1relaxos201a001.nii
01002M00T1relaxos301a001.nii
01002M00T1relaxouspios901a001.nii
01002M00T1relaxouspios1001a001.nii
Nota:在数组中,字段按数字顺序排序,因此1001
大于 901
。
Nota2:由于[[ ... =~ ... ]]
是一个条件,与正则表达式不匹配的文件名将被忽略。