以下在当前文件夹中工作正常,但我希望它也能扫描子文件夹。
for file in *.mp3
do
echo $file
done
这些答案中有太多使用外壳扩展来存储查找结果。这不是你应该轻易做的事情。
假设我有 30,000 首歌曲,这些歌曲的标题平均约为 30 个字符。让我们暂时不要讨论空白问题。
我的 find 将返回超过 1,000,000 个字符,而且我的命令行缓冲区很可能没有那么大。如果我做了这样的事情:
for file in $(find -name "*.mp3")
do
echo "some sort of processing"
done
问题(除了文件名中的空格)是您的命令行缓冲区将简单地从find
. 它甚至可能完全无声无息地失败。
这就是xargs
创建命令的原因。它确保命令行缓冲区永远不会溢出。它将xargs
根据需要多次执行以下命令以保护命令行缓冲区:
$ find . -name "*.mp3" | xargs ...
当然,使用xargs
这种方式仍然会阻塞空白,但是现代实现xargs
并find
有一种处理这个问题的方法:
$ find . -name "*.mp3 -print0 | xargs --null ...
如果您可以保证文件名中没有制表符或\n
(或双空格),则将 find 传递到 while 循环中会更好:
find . -name "*.mp3" | while read file
do
管道将while read
在命令行缓冲区满之前将文件发送到。更好的是,read file
读取整行并将在该行中找到的所有项目放入$file
. 它并不完美,因为read
仍然会在空白处中断,因此文件名如下:
I will be in \n your heart in two lines.mp3
I love song names with multiple spaces.mp3
I \t have \t a \t thing \t for \t tabs.mp3.
还是会失败。该$file
变量将它们视为:
I will be in
your heart in two lines.mp3
I love song names with multiple spaces.mp3
I have a thing for tabs.mp3.
为了解决这个问题,您必须find ... -print0
使用空值作为输入分隔符。然后要么更改IFS
为使用空值,要么使用-d\0
BASH shell 中的 while read 语句中的参数。
有很多方法可以给这只猫剥皮。我会自己调用 find 命令:
for file in $(find . -name '*.mp3') do
echo $file
TITLE=$(id3info "$file" | grep '^=== TIT2' | sed -e 's/.*: //g')
ARTIST=$(id3info "$file" | grep '^=== TPE1' | sed -e 's/.*: //g')
echo "$ARTIST - $TITLE"
done
如果文件名中有空格,那么最好使用-print0
查找选项;一种可能的方法是:
find . -name '*.mp3' -print0 | while read -d $'\0' file
do
echo $file
TITLE=$(id3info "$file" | grep '^=== TIT2' | sed -e 's/.*: //g')
ARTIST=$(id3info "$file" | grep '^=== TPE1' | sed -e 's/.*: //g')
echo "$ARTIST - $TITLE"
done
或者,您可以保存和恢复IFS
. 感谢 David W. 的评论,特别是指出while
循环版本还具有正确处理大量文件的好处,而将 a 扩展$(find)
为 for 循环的第一个版本将无法在某些时候工作,因为外壳扩展有限制。
这适用于大多数文件名(包括空格),但不适用于换行符、制表符或双空格。
find . -type f -name '*.mp3' | while read i; do
echo "$i"
done
这适用于所有文件名。
find . -type f -name '*.mp3' -print0 | while IFS= read -r -d '' i; do
echo "$i"
done
但是,如果您只想运行一个命令,则可以使用xargs
示例:
find . -type f -name '*.mp3' -print0 | xargs -0 -l echo
find . -name *.mp3 -exec echo {} \;
该字符串{}
被当前文件名替换,它出现在命令的参数中,而不仅仅是在单独的参数中,如在某些版本的 find 中。
请查看 find man 了解更多信息http://unixhelp.ed.ac.uk/CGI/man-cgi?find
听起来您正在寻找 find 命令。我还没有测试过这个,但是这些方面的东西:
files=(`find . -name *.mp3`)
for file in "${files[@]}"; do
echo $file TITLE="id3info "$file" | grep '^=== TIT2' | sed -e 's/.*: //g'" ARTIST="id3info "$file" | grep '^=== TPE1' | sed -e 's/.*: //g'"
done
编辑:使用数组使命令对于名称中带有空格的文件是安全的。