find ..
我知道当您由于“奇怪”的文件名而遇到将例如输出管道传输到的问题时,使用特定的分隔符(例如)来实际传递完整的文件名(例如)xargs
会有所帮助。并且,引用有问题的字符串以指定它们的边界“总是”有帮助的。\0
find foldername/ -type f -print0 | xargs -0 ...
但是,如果这些字符串(文件名)包含 bash 敏感字符'
(如,,,,,"
.. ?)并且您想使用一个字符串两次(即必须使用,并且需要在嵌套命令中注入这些字符串(即)?`
(
sh -c ..
$(CMD)
例如:
# create a file which should not exist but does
mkdir remove_afterwards
touch remove_afterwards/"some [\"strange\"] ('file')"
# this will work
find remove_afterwards/ -type f -print0 | xargs -0 -I{} sh -c 'echo "{}"'
# but this won't due to the nested command
find remove_afterwards/ -type f -print0 | xargs -0 -I{} sh -c 'echo "{}" $(stat -c "%s" "{}")'
stat: cannot statx 'remove_afterwards/some [strange] ('\''file'\'')': No such file or directory
remove_afterwards/some [strange] ('file')
我还没弄清楚如何逃离第二个{}
里面$()
。
有办法吗?
不可否认,一些具有功能的真实脚本会使这一切更容易编写和阅读,但我很好奇,历史上有这样一行代码值得努力去写这个问题。
分析
{}
出现问题是因为您在获取的shell 代码中传递了路径名(来自 的扩展)sh -c
。sh
不知道那里,它获取了已经扩展(通过){}
的参数,它将整个字符串解释为 shell 代码。{}
xargs
当嵌入
{}
到 shell 代码中时,没有固定的方法来引用它扩展为的内容。我的意思是:无论您想让奇怪的路径名如何工作("{}"
等等'{}'
),我总能想出一个会破坏您的特定代码的路径名;不仅会破坏您的代码,还会注入我的代码。例如,您的代码片段“有效”:可以通过创建一个以字面名称命名的文件来利用该漏洞
$(beep)
(创建此类文件的命令为touch 'remove_afterwards/$(beep)'
)。很可能beep
是无害的,但我本可以使用reboot
或rm something
。解决方案
安全的方法是将扩展
{}
作为单独的参数传递,该参数将成为您的位置参数sh -c
:(
find-sh
此处解释:中的第二个 sh 是什么sh -c 'some shell code' sh
?)解释
在解决方案中,我们
sh -c
解释的代码不包含{}
刚刚扩展的内容。代码是完全静态的,即事先知道,它就是单引号内的内容。扩展作为位置参数{}
传递给,知道它不是代码。无论您在何处需要 shell 代码中的值,都使用。对于外壳来说,重要的是使用单引号或转义,但稍后应该为内壳正确引用(请注意,内壳将看到外壳删除它认为特殊的引号和反斜杠后剩余的引号和反斜杠)。重点是它将自行扩展,仍然知道扩展的值不是 shell 代码。sh
sh
$1
$
$1
sh
$1
更广阔的前景
在 的情况下也存在同样的问题(有相同的解决方案)
find -exec
。比较是否可以安全使用find -exec sh -c
?一般来说,您应该始终选择静态 shell 代码(如果可能*),除非变量部分经过清理或故意设计为解释为 shell 代码。每当您想在 shell 代码中嵌入任何在将要解释代码的 shell“外部”扩展的内容时,这都适用。它不必是
{}
;例如,它可能是一个您想从内部使用的外部变量sh -c
:* 构建静态 shell 代码并非总是可行的。例如,通过 运行的命令
ssh
始终是单个字符串,由远程 shell 解释为 shell 代码;因此,如果您需要传递局部变量的值,那么除了将其嵌入 shell 代码之外别无他法。但仍有方法可以正确执行此操作(对于 Bash:请参阅${parameter@operator}
运算符何时为Q
)。暗示
如果您选择为 构建静态 shell 代码
sh -c
,我建议对整个代码使用单引号。唯一“有问题”的字符将是单引号本身(如果您需要它属于 shell 代码参数)。您可能会发现这很有用:如何方便地在 Bash 中对整个命令行使用单引号或转义?