如何在bash脚本中递归地执行foreach * .mp3文件?

时间:2013-04-10 15:40:19

标签: linux bash for-loop mp3

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

for file in *.mp3

do

echo $file

done

6 个答案:

答案 0 :(得分:8)

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

假设我有30,000首歌曲,这些歌曲的标题平均大约30个字符。我们现在还没有进入空白问题。

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

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

问题(除文件名中的空格外)是命令行缓冲区只会从find中删除溢出。它甚至可能完全无声地失败。

这就是创建xargs命令的原因。它确保命令行缓冲区永远不会溢出。它将根据需要在xargs之后执行命令,以保护命令行缓冲区:

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

当然,使用xargs这种方式仍然会占用空白区域,但xargsfind的现代实现方法可以解决此问题:

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

如果您可以保证文件名中没有选项卡或\n(或双重空格),那么将查找管理到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以使用空值,或使用BASH shell中while read语句中的-d\0参数。

答案 1 :(得分:5)

有很多方法可以给这只猫上皮。我会自己调用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循环版本还具有正确处理大量文件的好处,而第一个版本扩展了{{1由于shell扩展有限制,因此进入for循环将无法在某些时候起作用。

答案 2 :(得分:4)

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

字符串{}被在命令参数中出现的任何位置处理的当前文件名替换,而不仅仅是在单独的参数中,就像在某些版本的find中一样。

请查看查找人以获取更多信息http://unixhelp.ed.ac.uk/CGI/man-cgi?find

答案 3 :(得分:3)

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

答案 4 :(得分:3)

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

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

答案 5 :(得分:-1)

听起来你正在寻找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

编辑:使用数组可以使命令对于名称中带空格的文件安全。