在bash heredoc中使用变量

时间:2011-02-08 20:07:06

标签: bash variables sh 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中打开文件,该文件未使用sudo。

3 个答案:

答案 0 :(得分:220)

在回答您的第一个问题时,没有参数替换,因为您已将分隔符放在引号中 - the bash manual says

  

here-documents的格式为:

      <<[-]word
              here-document
      delimiter
     

无参数扩展,命令替换,算术扩展或   路径名扩展在 word 上执行。如果 word 中有任何字符   引用,分隔符是单词上的引用删除的结果,而   此文档中的行未展开。如果 word 没有引用,则全部   here-document的行经过参数扩展,命令替换和算术扩展。 [...]

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

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

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

答案 1 :(得分:82)

不要在<<EOF使用引号:

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

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

答案 2 :(得分:9)

作为此处早些答案的较晚推论,您可能最终遇到了想要插入 some 但不想插入 all 变量的情况。您可以通过使用反斜杠来避免美元符号和反引号来解决此问题;或者您可以将静态文本放入变量中。

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'都将禁用所有变量插值,并将此处文档转换为一段文字。

一个常见的任务是将局部变量与脚本结合在一起,而脚本应由其他外壳程序,编程语言或远程主机进行评估。

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"
: