这里记录为 bash 中的多行命令

这里记录为 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

它来到这里文档

$ $(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

它工作正常,
不幸的是,这不是结构化命令的情况

$ $(cat << EOF
→ for i in *
→ do 
→   stat $i
→ done
→ EOF)
-bash: for: command not found

我尝试过

$ bash $(cat << EOF
→ for i in *
→ do
→   stat $i
→ done
→ EOF)
bash: for: No such file or directory

是什么问题不允许 for 命令工作?

答案1

此处文档是重定向的一种形式。在命令中,您重定向到cat命令,然后尝试将输出用作命令替换中的命令。

  1. $i当此处文档的内容形成时,将对其进行扩展。这发生在文档中的循环实际运行之前很久。如果i未设置该变量,它将扩展为空字符串。您可以选择引用此处文档(通过引用第一个EOFas'EOF'\EOF),以便其中不进行任何扩展,或者显式转义$as\$以防止其扩展。
  2. 此处文档的内容将被解释为带有换行符分隔行的单个字符串。它不会经历通常的标记识别和解析普通命令所涉及的其他步骤,但会被分割成单独的单词,因为命令替换是不带引号的。特别是,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')
    

    除非您使用的是旧bash版本,例如 macOS 上的默认版本。

相反,这将是更好的操作选择,因为它避免将代码转换为需要重新解释的字符串,而是将文档作为内联 shell 脚本直接提供给 shell 解释器来执行。

bash <<'END_SCRIPT'
for i in *; do
    printf 'Filename: "%s"\n' "$i"
done
END_SCRIPT

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

相关内容