¿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.