write what end linux bash scripting heredoc

end - what is eof linux



¿Cómo funciona “cat<< EOF” en bash? (7)

Necesitaba escribir una secuencia de comandos para ingresar una entrada multilínea a un programa ( psql ).

Después de un poco de googlear, encontré los siguientes trabajos de sintaxis:

cat << EOF | psql ---params BEGIN; `pg_dump ----something` update table .... statement ...; END; EOF

Esto construye correctamente la cadena multilínea (desde BEGIN; hasta END; inclusive) y la canaliza como una entrada a psql .

Pero no tengo idea de cómo / por qué funciona, ¿alguien puede explicarlo?

Me refiero principalmente a cat << EOF , sé > salidas a un archivo, >> agrega a un archivo, < lee la entrada del archivo.

¿Qué hace exactamente << ?

¿Y hay una página de manual para ello?


POSIX 7

Kennytm citó a man bash , pero la mayor parte de eso también es POSIX 7: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04 :

Los operadores de redireccionamiento "<<" y "<< -" permiten el redireccionamiento de líneas contenidas en un archivo de entrada de shell, conocido como "documento aquí", a la entrada de un comando.

El documento aquí se tratará como una sola palabra que comienza después de la siguiente y continúa hasta que hay una línea que contiene solo el delimitador y una, sin caracteres entre ellos. Entonces comienza el siguiente documento aquí, si hay uno. El formato es el siguiente:

[n]<<word here-document delimiter

donde la n opcional representa el número de descriptor de archivo. Si se omite el número, el documento aquí se refiere a la entrada estándar (descriptor de archivo 0).

Si se cita un carácter cualquiera en palabra, el delimitador se formará mediante la eliminación de comillas en word y las líneas del documento aquí no se expandirán. De lo contrario, el delimitador será la palabra misma.

Si no se citan caracteres en palabra, todas las líneas del documento aquí se expandirán para la expansión de parámetros, la sustitución de comandos y la expansión aritmética. En este caso, la entrada se comporta como comillas dobles internas (consulte Cotizaciones dobles). Sin embargo, el carácter de comillas dobles (''"'') no se tratará especialmente dentro de un documento aquí, excepto cuando la comilla doble aparezca dentro de" $ () "," `` "o" $ {} ".

Si el símbolo de redirección es "<< -", todos los caracteres iniciales <tab> se eliminarán de las líneas de entrada y de la línea que contiene el delimitador final. Si se especifica más de un operador "<<" o "<< -" en una línea, el documento aquí asociado con el primer operador debe ser suministrado primero por la aplicación y debe ser leído primero por el shell.

Cuando se lee un documento aquí desde un dispositivo terminal y el shell es interactivo, debe escribir el contenido de la variable PS2, procesada como se describe en Variables de Shell, en un error estándar antes de leer cada línea de entrada hasta que se reconozca el delimitador.

Ejemplos

Algunos ejemplos aún no dados.

Cotizaciones previenen la expansión de parámetros

Sin comillas:

a=0 cat <<EOF $a EOF

Salida:

0

Con citas:

a=0 cat <<''EOF'' $a EOF

o (feo pero válido):

a=0 cat <<E"O"F $a EOF

Salidas:

$a

Guión elimina las pestañas iniciales

Sin guión:

cat <<EOF <tab>a EOF

donde <tab> es una pestaña literal y se puede insertar con Ctrl + V <tab>

Salida:

<tab>a

Con guión:

cat <<-EOF <tab>a <tab>EOF

Salida:

a

Por supuesto, esto existe para que pueda sangrar a su cat como el código que lo rodea, que es más fácil de leer y mantener. P.ej:

if true; then cat <<-EOF a EOF fi

Desafortunadamente, esto no funciona para los caracteres de espacio: POSIX aquí sangría de tab favorecida Yikes


En su caso, "EOF" se conoce como "Etiqueta aquí". Básicamente <<Here le dice al shell que va a ingresar una cadena multilínea hasta la "etiqueta" Here . Puede nombrar esta etiqueta como quiera, a menudo es EOF o STOP .

Algunas reglas sobre las etiquetas Here:

  1. La etiqueta puede ser cualquier cadena, mayúscula o minúscula, aunque la mayoría de las personas usan mayúsculas por convención.
  2. La etiqueta no se considerará como una etiqueta Aquí si hay otras palabras en esa línea. En este caso, simplemente se considerará parte de la cadena. La etiqueta debe estar sola en una línea separada, para ser considerada una etiqueta.
  3. La etiqueta no debe tener espacios iniciales o finales en esa línea para que se considere una etiqueta. De lo contrario, se considerará como parte de la cadena.

ejemplo:

$ cat >> test <<HERE > Hello world HERE <-- Not by itself on a separate line -> not considered end of string > This is a test > HERE <-- Leading space, so not considered end of string > and a new line > HERE <-- Now we have the end of the string


Esto no es necesariamente una respuesta a la pregunta original, sino un intercambio de algunos resultados de mis propias pruebas. Esta:

<<test > print.sh #!/bin/bash echo /$PWD echo $PWD test

producirá el mismo archivo que:

cat <<test > print.sh #!/bin/bash echo /$PWD echo $PWD test

Entonces, no veo el punto de usar el comando cat.


Esto se llama formato heredoc para proporcionar una cadena en stdin. Vea https://en.wikipedia.org/wiki/Here_document#Unix_shells para más detalles.

De man bash :

Aquí documentos

Este tipo de redirección le indica al shell que lea la entrada de la fuente actual hasta que se vea una línea que contiene solo una palabra (sin espacios en blanco).

Todas las líneas leídas hasta ese punto se utilizan como entrada estándar para un comando.

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 palabra , el delimitador es el resultado de la eliminación de comillas en word y las líneas en el documento aquí no se expanden. Si la palabra no tiene 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. En este último caso, la secuencia de caracteres /<newline> se ignora, y / debe utilizarse para citar los caracteres / , $ y ` .

Si el operador de redirección es <<- , todos los caracteres de tabulación iniciales se eliminan de las líneas de entrada y de la línea que contiene el delimitador . Esto permite que los documentos aquí en shell scripts sean sangrados de manera natural.


La sintaxis de cat <<EOF es muy útil cuando se trabaja con texto de varias líneas en Bash, por ejemplo. al asignar una cadena multilínea a una variable de shell, un archivo o una canalización.

Ejemplos de cat <<EOF uso de sintaxis cat <<EOF en Bash:

1. Asignar cadena multilínea a una variable de shell

$ sql=$(cat <<EOF SELECT foo, bar FROM db WHERE foo=''baz'' EOF )

La variable $sql ahora también contiene los caracteres de nueva línea. Puedes verificar con echo -e "$sql" .

2. Pase cadena multilínea a un archivo en Bash

$ cat <<EOF > print.sh #!/bin/bash echo /$PWD echo $PWD EOF

El archivo print.sh ahora contiene:

#!/bin/bash echo $PWD echo /home/user

3. Pase una cadena de líneas múltiples a una tubería en Bash

$ cat <<EOF | grep ''b'' | tee b.txt foo bar baz EOF

El archivo b.txt contiene líneas de bar y baz . La misma salida se imprime a stdout .


Vale la pena señalar que aquí los documentos también funcionan en bucles de bash. Este ejemplo muestra cómo obtener la lista de columnas de la tabla:

export postgres_db_name=''my_db'' export table_name=''my_table_name'' # start copy while read -r c; do test -z "$c" || echo $table_name.$c , ; done < <(cat << EOF | psql -t -q -d $postgres_db_name -v table_name="${table_name:-}" SELECT column_name FROM information_schema.columns WHERE 1=1 AND table_schema = ''public'' AND table_name =:''table_name'' ; EOF ) # stop copy , now paste straight into the bash shell ... output: my_table_name.guid , my_table_name.id , my_table_name.level , my_table_name.seq ,

O incluso sin la nueva línea.

while read -r c; do test -z "$c" || echo $table_name.$c , | perl -ne ''s//n//gm;print'' ; done < <(cat << EOF | psql -t -q -d $postgres_db_name -v table_name="${table_name:-}" SELECT column_name FROM information_schema.columns WHERE 1=1 AND table_schema = ''public'' AND table_name =:''table_name'' ; EOF ) # output: daily_issues.guid ,daily_issues.id ,daily_issues.level ,daily_issues.seq ,daily_issues.prio ,daily_issues.weight ,daily_issues.status ,daily_issues.category ,daily_issues.name ,daily_issues.description ,daily_issues.type ,daily_issues.owner


Usando tee en lugar de gato

No exactamente como una respuesta a la pregunta original, pero quería compartir esto de todos modos: tuve la necesidad de crear un archivo de configuración en un directorio que requiera derechos de root.

Lo siguiente no funciona para ese caso:

$ sudo cat <<EOF >/etc/somedir/foo.conf # my config file foo=bar EOF

porque la redirección se maneja fuera del contexto sudo.

Terminé usando esto en su lugar:

$ sudo tee <<EOF /etc/somedir/foo.conf >/dev/null # my config file foo=bar EOF