我有一堆目录,每个目录都包含一堆文件。通常我可以使用列出所有文件, ls */*.*
但这总是按照目录中的字母顺序列出它们,然后按照每个目录中的字母顺序列出它们。所以它总是会输出
dir1/file1.foo
dir1/file2.foo
...
dir2/file1.foo
dir2/file2.foo
...
...
dirN/file1.foo
dirN/file2.foo
...
我希望它做的是输出它,以便目录按某些特定顺序排列(例如,反向排列),但每个目录中的所有文件都按正常顺序排列,如下所示:
dirN/file1.foo
dirN/file2.foo
...
...
dir1/file1.foo
dir1/file2.foo
...
使用ls -r */*.*
不能达到我想要的效果,因为它会反转每个目录中的顺序以及目录本身的顺序。我尝试过使用,它可以ls `ls -r`
对没有空格的目录名执行我想要的操作,但对于有空格的目录名(不幸的是大多数目录名都有空格)不起作用。如果我尝试使用,ls "`ls -r`"
它会输出与目录名列表相同的内容ls -r
,但顺序相反。如何让 bash 执行我想要的操作?
答案1
使用sort
命令:
ls */* | sort -rst '/' -k1,1
和:
-t '/'
更改字段分隔符-r
进行反向排序-s
确保排序稳定(换句话说,它不会改变指定列之外的顺序-k1,1
将排序限制在第一列
这假设的输出ls */*
已经排序(应该是),否则sort
在中间添加一个简单的阶段。
答案2
通过 zsh 脚本
和 Linux/Unix 中的大多数事物一样,做事的方法不止一种。无论好坏,不管其价值如何,这都是做同样事情的另一种方式。
#!/usr/bin/env zsh
Dirs=(*(/D)) # (/D) = /(only directories) D(include hidden or dot)
for D in ${(O)Dirs} # (O) = reverse sort
do
L=(${D}/*(ND)) # (ND) = N(in case the glob is empty) D(see above)
[ ${#L} -eq 0 ] && { print "${D}/" ; continue } # if empty glob
print -l ${(o)L} # (o) = normal sort
done
print
zsh 内置命令-l
将每个元素输出到各自的行上。
D
如果不想列出隐藏的目录和文件,请删除glob 限定符。
答案3
补充@xeniod 的答案(开始是评论,但太长了):按照最初的要求,按相反顺序对目录进行排序,并按字母数字顺序对文件进行排序:
$ ls -d */* | sort -s -t '/' -k1,1rn -k2,2
或者,如果文件/目录有多个数字,例如,不仅仅是dir1..dir9
,还有dir10, dir11, dir101,...
和文件file1..file10..file101...
,您可以使用选项按“版本号”排序-V
,而不是只按字母/数字排序(仅支持 GNU 排序):
$ ls -d */* | sort -s -t '/' -k1,1rV -k2,2V
不过,理想情况下,您的目录和文件会有一些特殊字符作为前缀(或分隔)您想要排序的字段,如破折号(“ -
”),例如dir-23/file-1.txt
,dir-902/file-203.txt
等等,这样您就可以只对这些字段进行排序(数字后的非数字文本将被忽略):
$ ls -d */* | sort -s -t- -k2,2nr -k3,3n
关键点:
- 在分隔符之间分别添加多个
-k{begin,end}
排序列/
,例如,将第一列按字母数字排序,第二列按反向数字排序,第三列按“版本号”排序,等等 - 我
-d
在“ ”中添加了“ls -d */*
”,这样就不会列出目录内容,如果存在目录内容,则会破坏排序。或者,仅有的考虑文件,可以使用find */ -maxdepth 1 -type f
而不是ls
。) - 请注意,您实际上根本不关心排序中的“/”,这通常没问题。请注意,
-t {delim}
无论如何,您不能在单个排序中使用多个选项(例如-t '-' -k... -t '/'...
)