我怎样才能做一个bash脚本recursionforeach * .mp3文件?

以下在当前文件夹中正常工作,但我希望它也扫描子文件夹。

for file in *.mp3 do echo $file done 

太多的这些答案使用shell扩展来存储查找的结果。 这不是你应该做的事情。

假设我有三万首歌曲,这些歌曲的标题平均大约有30个字符。 我们现在甚至不进入空白问题。

我的发现将返回超过1,000,000个字符,而且很可能我的命令行缓冲区不是那么大。 如果我做了这样的事情:

 for file in $(find -name "*.mp3") do echo "some sort of processing" done 

问题(除了文件名中的空白)是你的命令行缓冲区将简单地从find溢出。 甚至可能会失败。

这就是创建xargs命令的原因。 它确保命令行缓冲区不会溢出。 它会根据需要多次执行下面的命令来保护命令行缓冲区:

 $ find . -name "*.mp3" | xargs ... 

当然,用这种方法使用xargs仍然会在空白处窒息,但是xargsfind现代实现可以解决这个问题:

 $ find . -name "*.mp3 -print0 | xargs --null ... 

如果你能保证文件名不会有制表符或者\n (或者双空格),那么在while循环中寻找一个find就更好了:

 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 \ta \t thing \t for \t tabs.mp3. 

仍然会失败。 $file变量aill看到他们:

 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更改为使用空值,或者在BASH shell的read语句中使用-d\0参数。

有很多方法来剥皮这只猫。 我会使用一个调用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循环版本也有正确的处理大量文件的好处,而第一个版本将$(find)扩展为for随着壳牌扩张的限制,回圈将无法正常工作。

 find . -name *.mp3 -exec echo {} \; 

在某些版本的find中,字符串{}被替换为当前文件名,而不管它在哪个单独的参数中都会出现在当前文件名中。

请查看查找人进一步的信息http://unixhelp.ed.ac.uk/CGI/man-cgi?find

 find . -name \*.mp3 | ( while read file; do echo $file done ) 

这适用于大多数文件名(包括空格),而不是换行符,制表符或双重空格。

 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命令。 我没有测试过这个,但是沿着这些线:

 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 

编辑:使用数组使命令安全的名称中有空格的文件。