在bash heredoc中使用变量

我试图在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。

144834 次浏览

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

here-documents的格式为:

      <<[-]word
here-document
delimiter

不进行参数展开、命令替换、算术展开或 路径名展开在上执行。如果中的任何字符为 被引用时,分隔符是对word删除引号的结果,而 此处文档中的行没有展开。如果不带引号,则所有 这里文档的行可以进行参数展开、命令替换和算术展开。[…]< / p >

如果你改变你的第一个例子使用<<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"
: