将目录列表传递给 find 命令

将目录列表传递给 find 命令

如何将目录列表传递给 find 命令?

想象一下您得到的列表为:

ls -d mydir*/

这将输出 mydir1、mydir2 等,但排除 otherdirs1、otherdirs2。

我想在列表上运行以下命令:

find <put here the name of each dir>  -type f -name "*.mp3" -print0 | xargs -0 ...

尝试分别在每个目录上运行此命令:

find -type f -name "*.mp3" -print0 |
xargs -0  mplayer -vo dummy -ao dummy -identify 2>/dev/null |
 perl -nle '/ID_LENGTH=([0-9\.]+)/ && ($t +=$1) && printf "%02d:%02d:%02d\n",$t/3600,$t/60%60,$t%60' |
 tail -n 1

这意味着:找到 mp3,运行 mplayer 获取每个文件的元数据,计算每个 mp3 文件的所有 ID_LENGTH 的总和,输出目录中所有 mp3 的总和。

答案1

ls -d准确列出您传递给它的内容(不存在的文件除外)。因此,假设至少有一个名称以 开头的目录mydir,那么这很简单

find mydir*/ -type f -name .mp3 -print0 | …

请注意,mydir*/匹配目录的符号链接,find并将遍历链接的目录。

通常xargs尽可能少地运行该命令,一次向其传递多个参数。如果您需要分别为每个文件运行命令,请这样告诉它:

find mydir*/ -type f -name .mp3 -print0 |
xargs -0 -n1 mplayer … |
perl …

或者做简单的事情并使用-exec的选项find。您确实失去了find单独过滤错误的能力mplayer

find mydir*/ -type f -name .mp3 -exec mplayer -vo dummy -ao dummy -identify {} \; 2>/dev/null |
perl …

顺便说一句,如果只需要最后一行,为什么要打印所有行呢?

… | perl -nle '/ID_LENGTH=([0-9\.]+)/ && ($t +=$1); END {printf "%02d:%02d:%02d\n",$t/3600,$t/60%60,$t%60}'

在运行后的 bash 中shopt -s globstar、运行后的 ksh 中set -o globstar或开箱即用的 zsh 中,您还可以用于**递归地匹配子目录中的文件。

mycommand mydir*/**/*.mp3
for f in mydir*/**/*.mp3; do …

这也匹配名称以 结尾的目录和符号链接.mp3。 Bash 遍历目录的符号链接,而 ksh 和 zsh 会遍历mydir*目录的符号链接,但在递归时省略符号链接。

for f in mydir*/**/*.mp3; do
  mplayer -vo dummy -ao dummy -identify "$f" 2>/dev/null
done | perl …

ksh93 和 zsh(但不是 bash、dash 或 pdksh)具有浮点运算,因此您甚至不需要调用 Perl 等其他工具来进行求和。

typeset -F length=0
for f in mydir*/**/*.mp3; do
  length+=$(mplayer -vo dummy -ao dummy -identify "$f" 2>/dev/null |
            sed -n 's/^ID_LENGTH=//p')
done | perl …
printf "%02d:%02d:%02d\n" $((t/3600)) $((t/60%60)) $((t%60))

相关内容