Redirige la salida de todos los comandos al archivo, no solo la última

11

Quiero agregar un encabezado a un archivo con echo, luego usar un comando para crear el resto del archivo. Esto significa que usaré dos comandos separados.

¿Cómo escribo el resultado de ambos comandos en un archivo con redirección?

He intentado

echo "header line" | cut -c 1-5 input_file > output_file

echo "header line"; cut -c 1-5 input_file > output_file

Esto solo redirige la salida del comando de corte.

El siguiente comando funciona, pero se siente torpe:

echo "header line" > output_file; cut -c 1-5 input_file >> output_file

¿Cuál es la forma inteligente de resolver mi problema?

El gato no divertido
fuente

Respuestas:

11

El problema aquí no es un problema con la redirección de Linux; más bien, es un malentendido fundamental de cómo funciona la tubería. La redirección aquí no funciona porque solo el corte se imprime en stdout. stdout para el comando echo se ha canalizado al stdin de cut (que no se usa en este caso ya que se especifica un archivo).

echo "header line" > output_file && cut -c 1-5 input_file >> output_file

es lo que quiere, y no poco elegante en absoluto (que sustituye el ;de &&manera que el comando de corte sólo se ejecutará si el encabezado se escribe correctamente, de esta manera no se ejecutará si no tiene permisos para crear o escribir a output_file )

También puede hacerlo todo en una subshell, por ejemplo.

(echo "header line"; cut -c 1-5 input_file) > output_file

pero no hay ningún beneficio real al hacerlo y con ejemplos más complejos puede causar problemas si no está familiarizado con el alcance de la subshell.

Si desea cortar para pasar stdin a stdout, puede intentar:

echo "header line" | cut -c 1-5 - input_file

(El guión es un atajo común para stdin)

Sin embargo, esto también realizará la operación de corte en stdin (lo que da como resultado una línea de encabezado de "encabezado"). Es difícil saber si esto es lo que quieres o no de la pregunta.

Sam Whited
fuente
13

Lo que buscas es:

{ echo "header line"; cut -c 1-5 input_file; } > output_file
  • Esta sintaxis no tiene efectos secundarios ya que los comandos se ejecutan en el shell actual, no en un subshell
  • Hay una delimitación clara de los comandos que van al archivo de salida
  • Se escala bien, ya que puede reescribirlo de esa manera:

{
  echo "header line"
  cut -c 1-5 input_file
  ... # insert new commands here
} > output_file

Si desea que la salida del error vaya al mismo archivo, puede modificar la última línea de esa manera:

} > output_file 2>&1

Gracias a Olivier Dulac por recordar ese consejo.

Si desea que alguna salida dentro del bloque vaya a su pantalla, puede usar esa sintaxis:

{
  echo "header line"
  echo "this line doesn't go to output_file" > /dev/tty
  cut -c 1-5 input_file
} > output_file
jlliagre
fuente
+1: es más claro e identifica claramente qué se redirige a dónde. Para redirigir todo (incluyendo error msg): { .... } > some_file 2>&1(se "clobber" some_file a no daban un golpe, pero anexados para que en su lugar, sólo cambia el. >En una >>: { ... } >> some_file 2>&1)
Olivier Dulac
4

Solo para completar las respuestas hay un ejecutivo.

exec > output_file
echo "header line"
cut -c 1-5 input_file
hildred
fuente
+1: en los scripts es muy común usar esto (menos en la línea de comando, ya que las cosas comienzan a ser confusas ^^)
Olivier Dulac
¿Podría alguien dar más detalles sobre esta solución? Puedo ver lo que está haciendo, pero no entiendo 'exec' en este contexto. Además, parece que hay que apagarlo de nuevo si el resto de su secuencia de comandos necesita stdout normal.
Joe
1
cuando usa exec en un script sin un comando, puede hacer la redirección de E / S en el exec que afecta el shell actual y todos los hijos futuros.
hildred
Gracias. No he visto eso antes. Creo que será muy útil.
Joe