以下在当前文件夹中工作正常,但我希望它也能扫描子文件夹。
for file in *.mp3
do
echo $file
done
答案 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
这种方式仍然会占用空白区域,但xargs
和find
的现代实现方法可以解决此问题:
$ 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
编辑:使用数组可以使命令对于名称中带空格的文件安全。