在 bash heredoc 中使用变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4937792/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 20:10:29  来源:igfitidea点击:

Using variables inside a bash heredoc

bashvariablesshheredoc

提问by Jon

I'm trying to interpolate variables inside of a bash heredoc:

我正在尝试在 bash heredoc 中插入变量:

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

This isn't working as I'd expect ($varis treated literally, not expanded).

这不像我期望的那样工作(按$var字面处理,而不是扩展)。

I need to use sudo teebecause creating the file requires sudo. Doing something like:

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

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

Doesn't work, because >outfileopens the file in the current shell, which is not using sudo.

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

回答by Mark Longair

In answer to your first question, there's no parameter substitution because you've put the delimiter in quotes - the bash manual says:

在回答您的第一个问题时,没有参数替换,因为您已将分隔符放在引号中 - 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 wordare quoted, the delimiteris the result of quote removal on word, and the lines in the here-document are not expanded. If wordis unquoted, all lines of the here-document are subjected to parameter expansion, command substitution, and arithmetic expansion. [...]

here-document 的格式为:

      <<[-]word
              here-document
      delimiter

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

If you change your first example to use <<EOFinstead of << "EOF"you'll find that it works.

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

In your second example, the shell invokes sudoonly with the parameter cat, and the redirection applies to the output of sudo catas the original user. It'll work if you try:

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

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

回答by mob

Don't use quotes with <<EOF:

不要使用引号<<EOF

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

Variable expansion is the default behavior inside of here-docs. You disable that behavior by quoting the label (with single or double quotes).

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

回答by tripleee

As a late corolloary to the earlier answers here, you probably end up in situations where you want somebut not allvariables to be interpolated. You can solve that by using backslashes to escape dollar signs and backticks; or you can put the static text in a variable.

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

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

Demo: https://ideone.com/rMF2XA

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

Note that any of the quoting mechanisms -- \____HEREor "____HERE"or '____HERE'-- will disable all variable interpolation, and turn the here-document into a piece of literal text.

请注意,任何引用机制——\____HERE"____HERE"'____HERE'——将禁用所有变量插值,并将此处文档转换为一段文字文本。

A common task is to combine local variables with script which should be evaluated by a different shell, programming language, or remote host.

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