¿Cómo se usa la redirección de salida en combinación con here-documents y cat?


56

Digamos que tengo un script que quiero canalizar a otro comando o redirigir a un archivo (canalizando shpara los ejemplos). Supongamos que estoy usando bash.

Podría hacerlo usando echo:

echo "touch somefile
echo foo > somefile" | sh

También podría hacer casi lo mismo usando cat:

cat << EOF
touch somefile
echo foo > somefile
EOF

Pero si reemplazo "EOF" con "EOF | sh", simplemente piensa que es parte del heredoc.

¿Cómo puedo hacer que catproduzca texto desde stdin y luego lo canalice a una ubicación arbitraria?


touches a menos que exista, ¿qué es exactamente lo que quieres? es solo leer el archivo de entrada y redirigir a otro con stdout?
— Rahul Patil

2
@RahulPatil, por supuesto, es inútil. Solo quería un ejemplo con más de una línea, para ilustrar mejor el heredoc. Y mira el ejemplo usando echo: me preguntaba cuál sería el equivalente de eso cat.
— strugee

Su ejemplo es crear un shscript a partir de múltiples cadenas y pasarlo directamente a sh. Encontré su Q buscando pasar la salida de texto de múltiples comandos, incluido un documento AQUÍ, directamente a un comando. Que es lo que hace el segundo ejemplo de la respuesta de Ash.
— Dave X

Respuestas:


91

Hay varias formas de hacer esto. Lo más simple es probablemente esto:

cat <<EOF | sh
touch somefile
echo foo > somefile
EOF

Otro, que es una sintaxis más agradable en mi opinión:

(
cat <<EOF
touch somefile
echo foo > somefile
EOF
) | sh

Esto también funciona, pero sin la subshell:

{
cat <<EOF
touch somefile
echo foo > somefile
EOF
} | sh

Más variaciones:

cat <<EOF |
touch somefile
echo foo > somefile
EOF
  sh

O:

{ cat | sh; } << EOF
touch somefile
echo foo > somefile
EOF

Por cierto, espero que el uso de caten su pregunta sea un marcador de posición para otra cosa. Si no, sácalo así:

sh <<EOF
touch somefile
echo foo > somefile
EOF

Lo que podría simplificarse a esto:

sh -c 'touch somefile; echo foo > somefile'

o:

sh -c 'touch somefile
echo foo > somefile'

Redirigir salida en lugar de tubería

sh >out <<EOF
touch somefile
echo foo > somefile
EOF

Utilizando catpara obtener el equivalente de echo test > out:

cat >out <<EOF
test
EOF

Múltiples documentos aquí

( cat; echo ---; cat <&3 ) <<EOF 3<<EOF2
hi
EOF
there
EOF2

Esto produce la salida:

hi
---
there

Esto es lo que está pasando:

  • El shell ve ( ... )y ejecuta los comandos incluidos en un subshell.
  • El gato y el eco son lo suficientemente simples. El cat <&3dice ejecutar cat con el descriptor de archivo (fd) 0 (stdin) redirigido desde fd 3; en otras palabras, elimine la entrada de fd 3.
  • Antes de que (...)se inicie, el shell ve que los dos documentos aquí redirigen y sustituyen fd 0 ( <<EOF) y fd 3 ( 3<<EOF2) con el lado de lectura de las tuberías
  • Una vez que se inicia el comando inicial, el shell lee su stdin hasta que se alcanza EOF y lo envía al lado de escritura de la primera tubería
  • Luego, hace lo mismo con EOF2 y el lado de escritura de la segunda tubería

dado el penúltimo ejemplo, ¿puede dar un ejemplo con redirección stdout en lugar de tubería?
— strugee

Edité la respuesta con un ejemplo de redireccionamiento; ¿Es este el formulario que quería editar? Si no, ¿puedes dar la primera línea de esa parte para aclarar?
— ceniza

1
Puede ayudar entender cómo el shell procesa esto. Cuando está evaluando la línea de comando y encuentra el << EOF, luego lee de la entrada estándar hasta que se encuentra una línea con solo EOF o el final de la entrada. Todo lo demás en la línea de comandos original que aún no se ha procesado continúa procesándose. Entonces, por ejemplo, es posible hacer algo como esto: (cat; echo ---; exec <&3; cat) <<EOF 3<<EOF2 >outy luego dar esa entrada de comando con dos bloques aquí en una fila.
— ceniza

Su explicación del procesamiento de shell fue interesante pero sobre mi cabeza :) Lo que quería saber era cuál sería el catequivalente de echo test > outusar un heredoc. Mientras que su ejemplo dado agregó una redirección al final de la tubería.
— strugee

1
@OlivierDulac: agregué el ejemplo heredoc múltiple a la respuesta.
— ceniza

1

Solo quiero señalar que usar meowes tan válido como EOF.

Este script se agregará Meow!a un archivo llamado cat:

#!/bin/sh
cat <<meow>> cat
Meow!
meow

Guardar como catsy hacerlo ejecutable con chmod +x cats, luego ejecutarlo con ./cats:

$ ./cats
$ cat cat
Meow!
$ ./cats
$ cat cat
Meow!
Meow!

Explicación:

  • cat <<meowes la sintaxis del documento aquí . Le indica al script que tome el bloque de texto que sigue a esta línea, hasta que encuentre la cadena meow. El contenido se generará (o se canalizará).
  • >> cattuberías al archivo nombrado cat.
  • Usar en >lugar de >>sobrescribiría el archivo en lugar de agregarlo.
  • Meow!es el contenido del documento aquí .
  • meowes el marcador final para el documento aquí . Los contenidos, con el uso de >>, se adjuntan a cat.

Tubería tanto a stdout como a un archivo:

Para hacer la tubería que solicita, no se requiere ningún documento aquí .

catno puede generar texto de salida y pasar el texto, pero teees una combinación perfecta para lo que está pidiendo:

echo echo | tee tee

Esto generará la cadena echoy escribirá echoen un archivo llamado tee.

También puede pasar la salida cat, si eso es parte del requisito, ya sea con:

echo echo | tee tee | cat </dev/stdin

O solo:

echo echo | tee tee | cat

Contenido del archivo:

$ cat tee
echo

1
Esto realmente no responde la pregunta. Tampoco >crea tuberías como su última viñeta implica.
— Strugee

2
@strugee, >puede crear tuberías zshcuando el mismo fd se redirige varias veces como en echo foo >&1 > teeo echo foo > tee | cat, donde zshimplementa un interno teepara alimentar la salida de echoambos caty el teearchivo.
— Stéphane Chazelas

Actualicé mi respuesta para responder mejor la pregunta.
— Alexander
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.