我有一个包含一些文件的目录.flac
:
[test]$ ls
'test file (with $ign & parentheses).flac' 'test file with spaces.flac'
我想对这些文件运行 ffmpeg 测试命令,我使用find
参数-exec
来实现此目的:
find ./ -type f -iregex '.*\.flac' -exec sh -c 'ffmtest=$(ffmpeg -v error -i "{}" -f null - 2>&1);if [ -n "$ffmtest" ];then echo -e "{}\n" $ffmtest;fi ' \;
对我的代码的一点解释:
find 命令将查找.flac
文件并将名称传递给 ffmpeg 命令进行测试。 ffmpeg 命令测试文件并向 stdout 返回错误字符串(因为最后重定向),或者如果没有发现错误则不返回任何内容,使用 ffmpeg 命令后面的 if 语句,以便如果ffmtest
变量包含错误则打印名称包含错误的文件的名称,后跟错误字符串(如果文件不包含错误,则不会打印任何内容)。
我的代码按预期工作,但如果文件名包含一个$
符号后跟一个字母,它就会失败,因此对于上面提到的测试文件,我得到的输出是这样的
[test]$ find ./ -type f -iregex '.*\.flac' -exec sh -c 'ffmtest=$(ffmpeg -v error -i "{}" -f null - 2>&1);if [ -n "$ffmtest" ];then echo -e "{}\n" $ffmtest;fi ' \;
./test file (with & parentheses).flac
./test file (with & parentheses).flac: No such file or directory
您可以看到没有符号的测试文件已正确测试,并且 ffmpeg 没有输出任何错误,但它甚至无法打开名称中$
带有符号的文件,您可以从 ffmpeg 的输出和 echo 中看到文件名是$
解释并且$
字母后面的符号被视为变量。
那么我怎样才能让 find 转义这些字符呢?
答案1
find . -type f -iregex '.*\.flac' -exec sh -c '
for file do
ffmtest=$(ffmpeg -v error -i "$file" -f null - 2>&1)
if [ -n "$ffmtest" ]; then
printf "%s\n" "$file" " $ffmtest"
fi
done' sh {} +
一些规则:
- 永远不要嵌入传递
{}
给(或任何语言解释器)的代码参数sh
,这将相当于代码注入漏洞(它也是不可移植的)。在你的例子中,情况并没有那么糟糕。但如果该文件被调用$(reboot).flac
,可能会产生更严重的后果。在这里,我们在内联脚本的参数中传递{}
( with+
,以便尽可能多地传递给sh
) forfind
来扩展,而不是在内联脚本的代码中。 - 始终在列表上下文中引用参数扩展。
- 不要用于
echo
任意数据。
答案2
会{}
按字面意思替换为文件名,因此请将其放在不会被特殊解析的地方。由于您已经在使用sh -c
,因此参数位置似乎很理想:
find ./ -type f -iregex '.*\.flac' -exec sh -c 'ffmtest=$(ffmpeg -v error -i "$1" -f null - 2>&1);if [ -n "$ffmtest" ];then echo -e "$1\n" $ffmtest;fi' -- {} \;