我试图在bash heredoc内插入变量:

var=$1
sudo tee "/path/to/outfile" > /dev/null << "EOF"
Some text that contains my $var
EOF

这不是我所期望的工作($var被字面上对待,而不是扩展)。

我需要使用sudo tee,因为创建文件需要sudo。做这样的事情:

sudo cat > /path/to/outfile <<EOT
my text...
EOT

不工作,因为>outfile在当前shell中打开文件,而当前shell没有使用sudo。


回答你的第一个问题,没有参数替换,因为你把分隔符放在引号中- bash手册说:

The format of here-documents is: <<[-]word here-document delimiter No parameter expansion, command substitution, arithmetic expansion, or pathname expansion is performed on word. If any characters in word are 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. [...]

如果您将第一个示例更改为使用<<EOF而不是<< "EOF",您会发现它是有效的。

在第二个示例中,shell仅使用参数cat调用sudo,重定向应用于作为原始用户的sudo cat的输出。如果你试着:

sudo sh -c "cat > /path/to/outfile" <<EOT
my text...
EOT

不要在<<EOF后使用引号:

var=$1
sudo tee "/path/to/outfile" > /dev/null <<EOF
Some text that contains my $var
EOF

变量展开是here-docs中的默认行为。您可以通过引用标签(使用单引号或双引号)来禁用该行为。


作为前面答案的一个后期推论,您可能会遇到这样的情况:您希望插入一些变量,但不是所有变量。你可以通过使用反斜杠来避免美元符号和反撇号来解决这个问题;或者你可以把静态文本放在一个变量中。

Name='Rich Ba$tard'
dough='$$$dollars$$$'
cat <<____HERE
$Name, you can win a lot of $dough this week!
Notice that \`backticks' need escaping if you want
literal text, not `pwd`, just like in variables like
\$HOME (current value: $HOME)
____HERE

演示:https://ideone.com/rMF2XA

注意,任何引用机制——\____HERE或"____HERE"或'____HERE'——都将禁用所有变量插值,并将HERE -document转换为一段文字文本。

一个常见的任务是将局部变量与脚本结合起来,脚本应由不同的shell、编程语言或远程主机进行计算。

local=$(uname)
ssh -t remote <<:
    echo "$local is the value from the host which ran the ssh command"
    # Prevent here doc from expanding locally; remote won't see backslash
    remote=\$(uname)
    # Same here
    echo "\$remote is the value from the host we ssh:ed to"
: