Bash - <<EOF 和 <<'EOF' 之间的区别

标签 bash heredoc

GNU Bash - 3.6.6 Here Documents

[n]<<[-]word
        here-document
delimiter

If any part of word is quoted, the delimiter is the result of quote removal on word, and the lines in the here-document are not expanded. If word is unquoted, all lines of the here-document are subjected to parameter expansion, command substitution, and arithmetic expansion, the character sequence \newline is ignored, and ‘\’ must be used to quote the characters ‘\’, ‘$’, and ‘`’.

如果我对 EOF 进行单引号,它就可以工作。我认为是因为要调用的 bash /bin/bash 进程获取未扩展的字符串,然后调用的进程解释这些行。

$ /bin/bash<<'EOF'
#!/bin/bash
echo $BASH_VERSION
EOF               
3.2.57(1)-release

但是,下面会导致错误。我以为 BASH_VERSION 会被扩展并将当前 bash 进程的版本传递给要调用的 /bin/bash 进程。但不工作。

$ /bin/bash<<EOF 
#!/bin/bash
echo $BASH_VERSION
EOF               
/bin/bash: line 2: syntax error near unexpected token `('
/bin/bash: line 2: `echo 5.0.17(1)-release'

最佳答案

/bin/bash<<EOF 
#!/bin/bash
echo $BASH_VERSION
EOF

您可以从错误消息中推断,heredoc 正在扩展为:

/bin/bash<<EOF 
#!/bin/bash
echo 5.0.17(1)-release
EOF

听起来这就是您所期望的:它正在扩展为外壳的版本。问题不在于heredoc 或扩展。就是不带引号的括号是语法错误。尝试只运行 echo手动命令,你会得到同样的错误:

$ echo 5.0.17(1)-release
bash: syntax error near unexpected token `('

要解决此问题,您可以添加额外的引号:

/bin/bash<<EOF 
echo '$BASH_VERSION'
EOF

这将起作用并打印外壳的版本。我使用单引号来证明这些引号将不会抑制变量扩展。外壳看不到这些引号。只有内壳可以。

(我还删除了 #!/bin/bash shebang 行。因为您明确调用 bash,所以不需要它。)

但是,引用并非 100% 可靠。 如果 $BASH_VERSION碰巧包含单引号,您会遇到问题。引号带括号( )安全,但它们并非万无一失。作为一项通用技术,如果您希望它完全安全无论游戏中有什么特殊角色,您都必须跳过一些丑陋的圈子。

  1. 使用printf '%q'转义所有特殊字符。

    /bin/bash <<EOF
    echo $(printf '%q' "$BASH_VERSION")
    EOF
    

    这将扩展为 echo 5.0.17\(1\)-release .

  2. 将其作为环境变量传入并使用<<'EOF'禁用脚本内的插值。

    OUTER_VERSION="$BASH_VERSION" /bin/bash <<'EOF'
    echo "$OUTER_VERSION"
    EOF
    

    这将是我的选择。我更喜欢使用 <<'EOF'尽可能形成。让父 shell 插入传递给子 shell 的脚本可能会令人困惑且难以推理。此外,显式 $OUTER_VERSION变量使发生的事情一目了然。

  3. 使用bash -c 'script'而不是heredoc,然后将版本作为命令行参数传入。

    bash -c 'echo "$1"' bash "$BASH_VERSION"
    

    我可能会用这个来编写单行脚本。

关于Bash - <<EOF 和 <<'EOF' 之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61648422/

相关文章:

bash - 如何避免 heredoc 扩展变量?

javascript - PHP 解析 heredoc 中的 JavaScript 内容

linux - 我如何将半命令分配给bash中的变量

php - php中heredoc与nowdoc的优点/不便

mysql - 从 Ubuntu Bash 访问 MySQL

ruby - 如何防止 capistrano 替换换行符?

Git:更改提交者信息

python - 使用 Python 通过排除隐藏文件来对两个目录执行 diff

bash - 未知名称的 Grep 文件名

linux - 想要 grep 行中的特定单词并在文件中的该行下方添加一个新行