239

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

4

3 回答 3

297

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

这里文档的格式是:

      <<[-]word
              here-document
      delimiter

不会对word执行参数扩展、命令替换、算术扩展或路径名扩展。如果word中的任何字符被引用,则 分隔符是 word 上去除引号的结果,并且 here-document 中的行不展开。如果word没有被引用,则 here-document 的所有行都经过参数扩展、命令替换和算术扩展。[...]

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

在您的第二个示例中,shellsudo仅使用参数调用cat,并且重定向适用于sudo cat原始用户的输出。如果您尝试,它将起作用:

sudo sh -c "cat > /path/to/outfile" <<EOT
my text...
EOT
于 2011-02-08T20:43:53.027 回答
116

不要使用引号<<EOF

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

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

于 2011-02-08T20:43:55.127 回答
56

作为此处较早答案的后期推论,您可能最终会遇到希望对一些但不是所有变量进行插值的情况。您可以通过使用反斜杠来转义美元符号和反引号来解决这个问题;或者您可以将静态文本放入变量中。

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

一个常见的任务是将局部变量与脚本结合起来,脚本应该由不同的 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"
:
于 2019-01-30T07:05:39.260 回答