Usando variables dentro de un bash heredoc

192

Estoy tratando de interpolar variables dentro de un bash heredoc:

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

Esto no funciona como esperaba ( $varse trata literalmente, no se expande).

Necesito usarlo sudo teeporque crear el archivo requiere sudo. Haciendo algo como:

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

No funciona porque >outfile abre el archivo en el shell actual, que no está usando sudo.

Jon
fuente
9
Esta es una confusión comprensible! Como se indica a continuación, al citar cualquier parte del delimitador se desactiva la expansión en el heredoc (como si estuviera dentro ''), pero al no citar el delimitador se activa la expansión (como si estuviera dentro ""). Sin embargo, su intuición es correcta en Perl, donde un heredoc con un identificador entre comillas simples se comporta como si estuviera entre comillas simples, uno con un identificador entre comillas dobles como si estuviera entre comillas dobles y otro con un identificador marcado como comillas inversas. ! Ver: perlop: << EOF
Nils von Barth

Respuestas:

252

En respuesta a su primera pregunta, no hay sustitución de parámetros porque ha puesto el delimitador entre comillas: el manual de bash dice :

El formato de los documentos aquí es:

      <<[-]word
              here-document
      delimiter

No se realiza expansión de parámetros, sustitución de comandos, expansión aritmética o expansión de nombre de ruta en Word . Si se citan caracteres en palabras , el delimitador es el resultado de la eliminación de comillas en palabras y las líneas en el documento aquí no se expanden. Si la palabra no está entre comillas, todas las líneas del documento aquí están sujetas a expansión de parámetros, sustitución de comandos y expansión aritmética. [...]

Si cambia su primer ejemplo para usar en <<EOFlugar de << "EOF", encontrará que funciona.

En su segundo ejemplo, el shell invoca sudosolo con el parámetro cat, y la redirección se aplica a la salida del sudo catusuario original. Funcionará si intentas:

sudo sh -c "cat > /path/to/outfile" <<EOT
my text...
EOT
Mark Longair
fuente
Si está interesado, también puede hacer esto como: (cat > /path/to/outfile) <<EOFen lugar desudo sh -c ... <<EOF
Voltaire
Por favor, dime que enterrado en Bash es una buena razón por la que esto es así.
Landon Kuhn
96

No use comillas con <<EOF:

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

La expansión variable es el comportamiento predeterminado dentro de here-docs. Deshabilita ese comportamiento citando la etiqueta (con comillas simples o dobles).

multitud
fuente
36

Como corolario tardío de las respuestas anteriores aquí, probablemente termines en situaciones en las que quieras que algunas pero no todas las variables se interpolen. Puede resolver eso mediante el uso de barras invertidas para escapar de los signos de dólar y los retrocesos; o puedes poner el texto estático en una 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

Demostración: https://ideone.com/rMF2XA

Tenga en cuenta que cualquiera de los mecanismos de cotización - \____HEREo "____HERE"o'____HERE' , deshabilitará toda interpolación de variables y convertirá el documento aquí en un texto literal.

Una tarea común es combinar variables locales con un script que debe ser evaluado por un shell, lenguaje de programación u host remoto diferente.

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"
:
tripleee
fuente
3
No estoy seguro de por qué esto fue rechazado, pero agrega una nota válida que no está cubierta en la respuesta ahora más votada.
Inian