如何将目录列表传递给 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))