将 find -exec 与包含美元符号 ($) 的文件名一起使用

将 find -exec 与包含美元符号 ($) 的文件名一起使用

我有一个包含一些文件的目录.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' -- {} \;

相关内容