此处将文档记录为 bash 中的多行命令

Abs*_*cDo 3 bash

我创建了一个片段来测试这里的文档

$ 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 命令工作的问题是什么?

Kus*_*nda 5

here-document 是一种重定向形式。在您的命令中,您重定向到该cat命令,然后尝试将输出用作命令替换中的命令。

  1. $i将在 here-document 的内容形成时展开。这发生在文档中的循环实际运行之前很久。如果i变量未设置,它将扩展为空字符串。您可以选择引用 here-document(通过引用第一个EOFas'EOF'\EOF),以便在其中进行任何扩展,或者显式转义$as\$以保护它免受扩展。
  2. here-document 的内容将被解释为带有换行分隔行的单个字符串。它不会经历通常的标记识别和解析普通命令所涉及的其他步骤,但由于命令替换未加引号,因此将被拆分为单个单词。特别是,for不会被识别为shell关键字。这就是您的第一个失败示例失败的原因。要重新评估字符串,您必须这样eval做,这将重新评估字符串,就像在命令行上给出的 shell 所做的那样。
  3. 最后一个示例将扩展为bash后跟多个单词。第一个词是for,所以bash希望运行for在当前目录中调用的 shell 脚本,但这样做失败了。

  4. 在所有案例中,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)

您的第一个示例有效,因为它是一个简单的命令。