我创建了一个片段来测试这里的文档
$ cat test101.sh
ls
$ bash test101.sh
bmdt.md brmdh.md fild.md test test101.sh test2 test5 testfile
breakfast.md exec file.md test.sh test12 test3 test7
Run Code Online (Sandbox Code Playgroud)
它来到这里文档
$ $(cat << EOF
? ls
? EOF)
bmdt.md brmdh.md fild.md test test101.sh test2 test5 testfile
breakfast.md exec file.md test.sh test12 test3 test7
Run Code Online (Sandbox Code Playgroud)
它工作正常,
不幸的是,结构化命令不是这种情况
$ $(cat << EOF
? for i in *
? do
? stat $i
? done
? EOF)
-bash: for: command not found
Run Code Online (Sandbox Code Playgroud)
我尝试过
$ bash $(cat << EOF
? for i in *
? do
? stat $i
? done
? EOF)
bash: for: No such file or directory
Run Code Online (Sandbox Code Playgroud)
不允许 for 命令工作的问题是什么?
here-document 是一种重定向形式。在您的命令中,您重定向到该cat
命令,然后尝试将输出用作命令替换中的命令。
$i
将在 here-document 的内容形成时展开。这发生在文档中的循环实际运行之前很久。如果i
变量未设置,它将扩展为空字符串。您可以选择引用 here-document(通过引用第一个EOF
as'EOF'
或\EOF
),以便在其中进行任何扩展,或者显式转义$
as\$
以保护它免受扩展。for
不会被识别为shell关键字。这就是您的第一个失败示例失败的原因。要重新评估字符串,您必须这样eval
做,这将重新评估字符串,就像在命令行上给出的 shell 所做的那样。最后一个示例将扩展为bash
后跟多个单词。第一个词是for
,所以bash
希望运行for
在当前目录中调用的 shell 脚本,但这样做失败了。
在所有案例中,bash
应该还抱怨说,在这里,文件没有正确结束(因为最后一行是EOF)
用尾随右括号,没有EOF
),说像
bash: warning: here-document at line 1 delimited by end-of-file (wanted `EOF')
Run Code Online (Sandbox Code Playgroud)
除非您使用的是旧bash
版本,例如 macOS 上的默认版本。
相反,这将是更好的操作选择,因为它避免将代码转换为需要重新解释的字符串,而是将文档作为内嵌 shell 脚本直接提供给 shell 解释器执行。
bash <<'END_SCRIPT'
for i in *; do
printf 'Filename: "%s"\n' "$i"
done
END_SCRIPT
Run Code Online (Sandbox Code Playgroud)
您的第一个示例有效,因为它是一个简单的命令。