如何按文件名的一部分对文件进行排序?

如何按文件名的一部分对文件进行排序?

鉴于以下文件:

ABC38388.SC01.StatueGrade_MKP
ABC38388.SC02.Statue_GKP
DEF38389.SC03.Statue_HKP
XYZ38390.SC00.Statue_WKP

我如何根据值列出它们SC,如下所示:

XYZ38390.SC00.Statue_WKP
ABC38388.SC01.StatueGrade_MKP
ABC38388.SC02.Statue_GKP
DEF38389.SC03.Statue_HKP

答案1

在这种特殊情况下,您的文件名不包含任何空格或其他奇怪的字符,您可以使用ls它并通过管道传输sort

$ ls -d -- *.SC* | sort -t. -k2
XYZ38390.SC00.Statue_WKP
ABC38388.SC01.StatueGrade_MKP
ABC38388.SC02.Statue_GKP
DEF38389.SC03.Statue_HKP

设置-t字段分隔符并-k2告知根据以第二sort字段开头的行部分进行排序(用于第二个字段-k2,2仅有的)。

对于更复杂的情况,您可以打印每个文件名,后跟 NULL 字符 ( ),然后使用其选项通过\0管道传递给 GNU以告诉它读取 NULL 分隔的行,最后使用将其更改回:sort-ztr\0\n

printf '%s\0' *SC* | sort -zt. -k2 | tr '\0' '\n'

答案2

oe使用 zsh,您可以使用或glob 限定符定义自己的 glob 排序顺序o+

ls -lUd -- *(oe['REPLY=${REPLY#*.SC}'])

或者:

bysc() REPLY=${REPLY#*.SC}
ls -lUd -- *(o+bysc)

排序函数接收文件名,$REPLY并返回一个字符串,$REPLY该字符串将根据通配符进行排序。在这里,我们返回第一次出现 的右侧的文件名部分.SC(如果不包含 ,则返回完整文件名.SC)。

答案3

在 GNU 系统上并使用zshbash作为 shell,使用以下命令:

find -maxdepth 1 -type f -print0 | sort -z -t. -k3 | \
while IFS="" read -r -d "" f; do
  basename "$f"
done

  • find搜索当前目录 ( ) 中的文件-maxdepth 1并以空字节分隔 ( -print0) 打印它们。
  • sort读取以空字节分隔 ( ) 的输入,并对以点 ( ) 分隔的-z第三个字段 ( ) 开始的记录部分进行排序。-k3-t.
  • while读取输入
    • basename打印不带路径的名称

答案4

我会——就像我经常做的那样——建议perl

perl有一个排序函数,可让您指定比较函数。此比较函数是采用两个值并返回或 的任何测试-1,具体取决于相对位置。01

它迭代列表,将每个值设置为$a$b并为每个元素“进行测试”。

所以默认情况下:

$a cmp $b 

用于字符串比较或sort { $a <=> $b }数字比较。

但因此,您可以应用任意复杂的自定义排序标准:

#!/usr/bin/perl
use strict;
use warnings;

sub sort_by_sc {
   my ( $a_sc ) = $a =~ m/SC(\d+)/;
   my ( $b_sc ) = $b =~ m/SC(\d+)/;
   return $a_sc <=> $b_sc;
}


my @file_list = qw ( 
    ABC38388.SC01.StatueGrade_MKP
    ABC38388.SC02.Statue_GKP
    DEF38389.SC03.Statue_HKP
    XYZ38390.SC00.Statue_WKP
);

print sort sort_by_sc @file_list;

或者简化为一行,读取STDIN或文件(换行符分隔,通常就足够了):

perl -e 'print sort {@x = map {/SC(\d+)/}($a,$b); $x[0] <=> $x[1]} <>'

glob您可以改为向其提供目录模式的结果:

perl -e 'print sort {@x = map {/SC(\d+)/}($a,$b); $x[0] <=> $x[1]} glob ( "*SC*")'

相关内容