以下在当前文件夹中正常工作,但我希望它也扫描子文件夹。
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
仍然会在空白处窒息,但是xargs
和find
现代实现可以解决这个问题:
$ 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
编辑:使用数组使命令安全的名称中有空格的文件。