12

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

for file in *.mp3

do

echo $file

done
4

5 回答 5

10

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

假设我有 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这种方式仍然会阻塞空白,但是现代实现xargsfind有一种处理这个问题的方法:

$ 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\0BASH shell 中的 while read 语句中的参数。

于 2013-04-10T16:11:10.027 回答
9

有很多方法可以给这只猫剥皮。我会自己调用 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 循环的第一个版本将无法在某些时候工作,因为外壳扩展有限制。

于 2013-04-10T15:42:37.820 回答
5

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

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
于 2013-04-10T15:42:43.110 回答
4
find . -name *.mp3 -exec echo {} \;

该字符串{}被当前文件名替换,它出现在命令的参数中,而不仅仅是在单独的参数中,如在某些版本的 find 中。

请查看 find man 了解更多信息http://unixhelp.ed.ac.uk/CGI/man-cgi?find

于 2013-04-10T22:33:16.807 回答
-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

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

于 2013-04-10T15:41:57.223 回答