为什么文件命令在子命令中运行时无法打开文件,而basename之类的命令工作得很好?
ls
file1 file2 file3
find * -exec echo $(basename {}) \;
file1
file2
file3
find * -exec echo $(file {}) \;
file1: cannot open `file1' (No such file or directory)
file2: cannot open `file2' (No such file or directory)
file3: cannot open `file3' (No such file or directory)
find * -exec file {} \;
file1: empty
file2: empty
file3: empty
答案 0 :(得分:2)
因为子命令在 find
之前运行,所以这是完全正常和预期的行为。那就是:
find * -exec echo $(basename {}) \;
......先跑......
basename {}
...返回字符串{}
,发出命令:
find * -exec echo {} \;
...根本不会为三个单独的文件中的每一个运行basename
。
同样,find * -exec echo $(file {}) \;
首先运行file {}
,并且由于这会在stdout 上返回错误消息,请将该错误替换为稍后由find
运行的命令。
如果你想在find
启动的shell中运行某些东西,你需要告诉find
启动那个shell:
# note that {} is a separate argument; this is important for security reasons.
find . -exec sh -c 'echo $(basename "$1")' _ {} \;
......顺便说一下,这是一个非常非常愚蠢且不必要的低效写作方式:
find . -exec basename {} \;
顺便说一下,如果你做需要一个shell,你可以通过传递一个shell多个参数来提高效率:
find . -exec 'for arg; do basename "$arg"; done' _ {} +
...或者您可以直接在父进程中执行循环,而不是完全使用find -exec
:
# note that this requires a bash, not /bin/sh, shebang.
while IFS= read -r -d '' filename <&3; do
basename "$filename"
done 3< <(find . -print0)
以下看起来就像它有效:
# THIS IS EVIL; DO NOT DO THIS
find . -exec sh -c 'echo $(basename "{}")' \;
...但是,它实际上会在您的系统中引入严重的安全漏洞。为什么?假设有人制作了这样的文件:
touch $'$(touch i-am-evil)\'$(touch i-am-evil)\''
...当你的find
命令发生时,它会运行:
echo $(basename "$(touch i-am-evil)'$(touch i-am-evil)'")
...并且touch i-am-evil
开始运行。 (将其替换为攻击者可能希望在运行find
的用户的权限的情况下在您的系统上执行的任意命令。)