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:
- La etiqueta puede ser cualquier cadena, mayúscula o minúscula, aunque la mayoría de las personas usan mayúsculas por convención.
- 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.
- 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