我正在尝试制作一个小脚本来转换音乐库中的一些文件。
但是如果我做类似的事情:
#!/usr/bin/zsh
for x in $(find -name "*.m4a");
do
echo $x;
done
在包含以下内容的文件夹中翻译时:
foo\ bar.m4a
它会返回:
foo
bar.m4a
如何防止 for 循环将空格字符解释为分隔符?
我可以用
$(find -name "*.m4a")
替换 $(find -name "*.m4a" | sed "s/ /_/g")
,然后在循环内以另一种方式使用 sed
,但是如果文件名/路径已经包含下划线(或者我可以使用其他字符来代替下划线)怎么办?
有什么想法吗?
您可以通过双引号来防止命令替换的单词拆分:
#!/usr/bin/zsh
for x in "$(find . -name "*.m4a")"
do
echo "$x"
done
注意命令替换中的双引号与它之外的双引号不冲突(实际上我以前从未注意到这一点)。如果您觉得单引号更具可读性,您可以像在
"$(find -name '*.m4a')"
中一样轻松地使用单引号。无论如何,我通常在 find
初选中使用单引号。
出于同样的原因,在循环体内引用也很重要。它将确保
x
的值作为单个参数传递。
但这绝对是一个混合的、弗兰肯斯坦式的解决方案,循环
find
的输出通常被认为是不安全的。您最好使用 shell 文件名生成 或使用 find
,如下所示:
find . -name '*.mp3' -exec echo {} \;
您可以添加额外的
-exec
primaries,它们将像由 &&
分隔的 shell 命令一样执行。
如果您绝对必须循环
find
输出,请使用空分隔输出而不是换行分隔:
touch 'a b.txt'
touch $'b\nc.txt'
touch $'d\te.txt'
find . -name '*.txt' -print0 \
| while IFS= read -r -d $'\0' fname; do
printf '%s\n\n' "$fname"
done
在这里使用
zsh
的通配设施而不是find
.
for x in **/*.m4a; do
echo "$x"
done
在
$x
的默认设置下,在循环体中引用zsh
是可选的,但无论如何这样做并不是一个坏主意。
我发现了
如这里所建议:https://askubuntu.com/questions/344407/how-to-read-complete-line-in-for-loop-with-spaces
我可以将 IFS(内部字段分隔符)设置为 ' '.
所以这有效:
#!/usr/bin/zsh
IFS=$'\n'
for x in $(find -name "*.m4a");
do
echo $x;
done
我希望这可以帮助别人!