¿Cómo puedo escribir un heredoc a un archivo en el script Bash?


¿Cómo puedo escribir un documento here en un archivo en el script Bash?

Author: Andre Figueiredo, 2010-06-02

7 answers

Lea la Guía Avanzada de Scripts de Bash Capítulo 19. Aquí Documentos.

Aquí hay un ejemplo que escribirá el contenido en un archivo en /tmp/yourfilehere

cat << EOF > /tmp/yourfilehere
These contents will be written to the file.
        This line is indented.
EOF

Tenga en cuenta que el 'EOF' final (El LimitString) no debe tener ningún espacio en blanco delante de la palabra, porque significa que el LimitString no será reconocido.

En un script de shell, es posible que desee usar sangría para hacer que el código sea legible, sin embargo, esto puede tener el efecto no deseado de sangría del texto dentro su documento aquí. En este caso, use <<- (seguido de un guion) para deshabilitar las pestañas iniciales ( Tenga en cuenta que para probar esto necesitará reemplazar el espacio en blanco inicial con un carácter de tabulación, ya que no puedo imprimir caracteres de tabulación reales aquí.)

#!/usr/bin/env bash

if true ; then
    cat <<- EOF > /tmp/yourfilehere
    The leading tab is ignored.
    EOF
fi

Si no desea interpretar variables en el texto, utilice comillas simples:

cat << 'EOF' > /tmp/yourfilehere
The variable $FOO will not be interpreted.
EOF

Para canalizar el heredoc a través de una canalización de comandos:

cat <<'EOF' |  sed 's/a/b/'
foo
bar
baz
EOF

Salida:

foo
bbr
bbz

... o para escribir el el heredoc a un archivo usando sudo:

cat <<'EOF' |  sed 's/a/b/' | sudo tee /etc/config_file.conf
foo
bar
baz
EOF
 781
Author: Stefan Lasiewski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-27 09:44:37

En lugar de usar cat y la redirección de E/S, podría ser útil usar tee en su lugar:

tee newfile <<EOF
line 1
line 2
line 3
EOF

Es más conciso, además, a diferencia del operador de redirección, se puede combinar con sudo si necesita escribir en archivos con permisos de root.

 112
Author: Livven,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-13 17:35:13

Nota:

La pregunta (¿cómo escribir un documento here (aka heredoc) en un archivo en un script bash?) tiene (al menos) 3 dimensiones independientes principales o preguntas:

  1. ¿Desea sobrescribir un archivo existente, anexarlo a un archivo existente o escribir en un archivo nuevo?
  2. ¿Su usuario u otro usuario (por ejemplo, root) posee el archivo?
  3. ¿Desea escribir el contenido de su heredoc literalmente, o hacer que bash interprete las referencias de variables dentro de su heredoc?

(Hay otras dimensiones/subcuestiones que no considero importantes. ¡Considera editar esta respuesta para añadirlas! Aquí están algunos de los combinaciones más importantes de las dimensiones de la pregunta mencionada anteriormente, con varios identificadores delimitadores diferentes {no hay nada sagrado en EOF, solo asegúrese de que la cadena que usa como su identificador delimitador no ocurra dentro de su heredoc:

  1. Para sobrescribir un archivo existente (o escribir en un archivo nuevo) que usted posee, sustituyendo las referencias de variables dentro del heredoc:

    cat << EOF > /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, with the variable contents substituted.
    EOF
    
  2. Para anexar un archivo existente (o escribir a un nuevo archivo) que usted posee, sustituyendo las referencias de variables dentro del heredoc:

    cat << FOE >> /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, with the variable contents substituted.
    FOE
    
  3. Para sobrescribir un archivo existente (o escribir en un archivo nuevo) que usted posee, con el contenido literal del heredoc:

    cat << 'END_OF_FILE' > /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, without the variable contents substituted.
    END_OF_FILE
    
  4. Para anexar un archivo existente (o escribir en un nuevo archivo) que usted posee, con el contenido literal del heredoc:

    cat << 'eof' >> /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, without the variable contents substituted.
    eof
    
  5. Para sobrescribir un archivo existente (o escribir en un nuevo archivo) propiedad de root, sustituyendo las referencias de variables dentro del heredoc:

    cat << until_it_ends | sudo tee /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, with the variable contents substituted.
    until_it_ends
    
  6. Para anexar un archivo existente (o escribir en un nuevo archivo) propiedad de user = foo, con el contenido literal del heredoc:

    cat << 'Screw_you_Foo' | sudo -u foo tee -a /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, without the variable contents substituted.
    Screw_you_Foo
    
 42
Author: TomRoche,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:25

Para construir sobre la respuesta de @Livven, aquí hay algunas combinaciones útiles.

  1. Sustitución de variables, pestaña inicial retenida, sobrescribir archivo, echo a stdout

    tee /path/to/file <<EOF
    ${variable}
    EOF
    
  2. Sin sustitución de variables , se conserva la pestaña inicial, sobrescribe el archivo, hace eco a la salida estándar

    tee /path/to/file <<'EOF'
    ${variable}
    EOF
    
  3. Sustitución de variables, pestaña inicial eliminada , sobrescribir archivo, echo a salida estándar

    tee /path/to/file <<-EOF
        ${variable}
    EOF
    
  4. Sustitución de variables, pestaña inicial retained, append to file , echo to stdout

    tee -a /path/to/file <<EOF
    ${variable}
    EOF
    
  5. Sustitución de variables, tabulación inicial retenida, sobrescribir archivo, sin eco a salida estándar

    tee /path/to/file <<EOF >/dev/null
    ${variable}
    EOF
    
  6. Lo anterior se puede combinar con sudo también

    sudo -u USER tee /path/to/file <<EOF
    ${variable}
    EOF
    
 18
Author: go2null,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:36

Cuando se requieren permisos de root

Cuando se requieren permisos de root para el archivo de destino, use |sudo tee en lugar de >:

cat << 'EOF' |sudo tee /tmp/yourprotectedfilehere
The variable $FOO will *not* be interpreted.
EOF
 14
Author: Serge Stroobandt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-21 13:55:57

Para las futuras personas que puedan tener este problema, el siguiente formato funcionó:

(cat <<- _EOF_
        LogFile /var/log/clamd.log
        LogTime yes
        DatabaseDirectory /var/lib/clamav
        LocalSocket /tmp/clamd.socket
        TCPAddr 127.0.0.1
        SelfCheck 1020
        ScanPDF yes
        _EOF_
) > /etc/clamd.conf
 12
Author: Joshua Enfield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-03 14:58:43

Como ejemplo podría usarlo:

Primero (hacer una conexión ssh):

while read pass port user ip files directs; do
    sshpass -p$pass scp -o 'StrictHostKeyChecking no' -P $port $files $user@$ip:$directs
done <<____HERE
    PASS    PORT    USER    IP    FILES    DIRECTS
      .      .       .       .      .         .
      .      .       .       .      .         .
      .      .       .       .      .         .
    PASS    PORT    USER    IP    FILES    DIRECTS
____HERE

Segundo (ejecutar comandos):

while read pass port user ip; do
    sshpass -p$pass ssh -p $port $user@$ip <<ENDSSH1
    COMMAND 1
    .
    .
    .
    COMMAND n
ENDSSH1
done <<____HERE
    PASS    PORT    USER    IP
      .      .       .       .
      .      .       .       .
      .      .       .       .
    PASS    PORT    USER    IP    
____HERE

Tercero (ejecutar comandos):

Script=$'
#Your commands
'

while read pass port user ip; do
    sshpass -p$pass ssh -o 'StrictHostKeyChecking no' -p $port $user@$ip "$Script"

done <<___HERE
PASS    PORT    USER    IP
  .      .       .       .
  .      .       .       .
  .      .       .       .
PASS    PORT    USER    IP  
___HERE

Forth (usando variables):

while read pass port user ip fileoutput; do
    sshpass -p$pass ssh -o 'StrictHostKeyChecking no' -p $port $user@$ip fileinput=$fileinput 'bash -s'<<ENDSSH1
    #Your command > $fileinput
    #Your command > $fileinput
ENDSSH1
done <<____HERE
    PASS    PORT    USER    IP      FILE-OUTPUT
      .      .       .       .          .
      .      .       .       .          .
      .      .       .       .          .
    PASS    PORT    USER    IP      FILE-OUTPUT
____HERE
 2
Author: MLSC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-16 10:27:52