如何按名称的一部分(特别是括号中包含的元素或由定界符分隔的元素)对文件或目录进行排序?
我追求两个独立的解决方案,一个用于具有如下名称结构的目录:
Badger Bodger (2001)
Charlie Fisher's (1989)
以及以下格式的文件:
Could Be A Title.2001.prop.ext1
Another Potential Title.1989.prop.ext2
在这两种情况下,带有 1989 的目录或文件应该在 2001 之前。对于目录,排序依据元素在括号中。对于文件,它是分隔符后的前四位数字.
。
我在 Debian 8.0 上运行 bash。请寻找命令行解决方案。如果用 bash 编写,可以接受简短的脚本。
答案1
考虑以下文件:
$ ls --quoting-style=c -1 *.*
"Another Potential Title.1989.prop.ext2"
"being there.2000.prop.ext3"
"Could Be A Title.2001.prop.ext1"
"Yet Another Potential Title.1989.prop.ext2"
按年份排序:
$ ls --quoting-style=c *.* | sort -t. -k2n
"Another Potential Title.1989.prop.ext2"
"Yet Another Potential Title.1989.prop.ext2"
"being there.2000.prop.ext3"
"Could Be A Title.2001.prop.ext1"
对于您的目录,类似的方法也有效:
$ ls --quoting-style=c -d */ | sort -t'(' -k2n
"Charlie Fisher's (1989)/"
"Badger Bodger (2001)/"
由于选项--quoting-style=c
,这种方法甚至适用于包含换行符或其他难懂字符的文件名。如果您的当然您的文件名不包含换行符,您可以省略此选项。
怎么运行的
sort
可以将输入行拆分为字段。该-t
选项设置字段分隔符。对于文件,字段分隔符为,而.
对于目录,字段分隔符为(
。该-k
选项确定对哪个字段进行排序。对于上述两种情况,我们要求sort
在第二个字段上按数字排序。
答案2
我假设您确定所有文件名都不包含换行符,或者您有某种方法来处理这种可能性。首先,使用以下命令操作文件名sed
:
%命令_to_list_filenames| sed ‘s/.*\.\([0-9][0-9][0-9][0-9]\)\..*/\1.&/’ 2001.可以是标题.2001.prop.ext1 1989.另一个潜在的标题.1989.prop.ext2 %
s
命令中的 (substitute) 命令将sed
每一行视为下列序列:
- 任意数量的任意字符 (
.*
), - 实际期限(
\.
), - 四位数 (
[0-9][0-9][0-9][0-9]
), - 另一个实际时期(
\.
),以及 - 另一个字符序列 (
.*
)。
请注意,年份 ( [0-9][0-9][0-9][0-9]
) 被括在\(
和之间\)
,形成一个组。然后,替换命令将字符串替换为
- 分组字符,即年份(
\1
), - 句号 (
.
),以及 - 整个输入行(
&
)。
然后只需按年份(现在出现在行首)对行进行排序并去掉年份即可:
%命令_to_list_filenames| sed 's/.*\.\([0-9][0-9][0-9][0-9]\)\..*/\1.&/' | 排序 1989.另一个潜在的标题.1989.prop.ext2 2001.可以是标题.2001.prop.ext1 %命令_to_list_filenames| sed 's/.*\.\([0-9][0-9][0-9][0-9]\)\..*/\1.&/' | 排序 | sed's/^[0-9][0-9][0-9][0-9].//' 另一个潜在的标题.1989.prop.ext2 可能是标题.2001.prop.ext1 %
可以简单修改该sed
命令以处理其他模式。并且sed
可以从文件而不是管道获取输入:
% sed 's/.*(\([0-9][0-9][0-9][0-9]\)).*/\1.&/' list_of_directory_names | sort |
sed 's/^[0-9][0-9][0-9][0-9].//'
Charlie Fisher's (1989)
Badger Bodger (2001)
%
请注意,这适用于包含句点或括号的文本,例如,
Dr. Strangelove.1964.foo
Mrs. Doubtfire.1993.bar
只要它们后面不是四位数字。
.*
如果你愿意的话,你可以省略第二步:
%命令_to_list_filenames| sed ‘s/.*\.\([0-9][0-9][0-9][0-9]\)\./\1.&/’ 2001.可以是标题.2001.prop.ext1 1989.另一个潜在的标题.1989.prop.ext2 %