Comando y eco del gato

14

Me gustaría concatenar la salida de echo con el contenido de un archivo. He intentado el siguiente comando:

echo "abc" | cat 1.txt > 2.txt

pero el 2.txtarchivo solo contiene el contenido de 1.txt. ¿Por qué no funciona?

Ringger81
fuente
3
Los programas catsolo leen desde la entrada estándar si no tienen ningún argumento de nombre de archivo.
Barmar

Respuestas:

23

No funciona porque el catprograma en su secuencia de tubería no recibió instrucciones de leer la echosalida del programa desde la entrada estándar.

Puede usarlo -como un nombre de pseudo archivo para indicar la entrada estándar a cat. Desde man catuna instalación de msys2:

EXAMPLES
       cat f - g
              Output f's contents, then standard input, then g's contents.

Así que intenta

echo "abc" | cat - 1.txt > 2.txt

en lugar.

mvw
fuente
21

Como señalaron otros, su comando original falla porque cat 1.txtignora su entrada estándar. Indique que debería ser su primer argumento ( cat - 1.txt) o utilice la redirección de bloque para redirigir echo abc y cat 1.txt juntos. Esto es:

{ echo abc; cat 1.txt; } > 2.txt 

Extracto relevante del manual ( man bash):

Comandos
compuestos Un comando compuesto es uno de los siguientes. En la mayoría de los casos, una lista en la descripción de un comando puede estar separada del resto del comando por una o más líneas nuevas, y puede ser seguida por una nueva línea en lugar de un punto y coma.

(lista)

    La lista se ejecuta en un entorno de subshell (ver ENTORNO DE EJECUCIÓN DE MANDOS a continuación). Las asignaciones variables y los comandos incorporados que afectan el entorno del shell no permanecen vigentes una vez que se completa el comando. El estado de retorno es el estado de salida de la lista.

{lista; }

    La lista simplemente se ejecuta en el entorno de shell actual.  La lista debe terminarse con una nueva línea o punto y coma. Esto se conoce como un comando de grupo . El estado de retorno es el estado de salida de la lista . Tenga en cuenta que, a diferencia de los metacaracteres (y ), {y }son palabras reservadas y deben aparecer donde se permite reconocer una palabra reservada. Como no causan un salto de palabra, deben estar separados de la lista por espacios en blanco u otro metacarácter de shell.

La primera opción (entorno de subshell) tiene muchos efectos secundarios, la mayoría de los cuales son irrelevantes para su escenario; sin embargo, si todo lo que necesita es redireccionar la salida de un grupo de comandos, entonces se prefiere la Opción # 2 aquí (comando de grupo).

Nubarke
fuente
7
( echo "abc"; cat 1.txt ) > 2.txt

Conectó la salida de eco a cat, pero cat no tenía uso para la entrada y la ignoró. Ahora los comandos se ejecutan uno tras otro, y su salida se agrupa (los paréntesis) y se dirige a 2.txt.

Gerard H. Pille
fuente
1
Esta respuesta puede mejorarse explicando cómo funciona y por qué el intento original del OP no funciona.
Bob
OK, lo probé.
Gerard H. Pille
55
Aquí no se requiere expresamente una subshell, quizás sería mejor usar un comando de grupo. Vea mi respuesta para más detalles.
Nubarke
Ah, pero nunca usaría bash.
Gerard H. Pille el
1
@ GerardH.Pille: Si bien la respuesta de Daniel cita bash(1), describe el comportamiento que cada shell compatible con POSIX debe admitir.
G-Man dice 'reinstalar a Monica' el
2

Su comando cat 1.txtno hace nada con la salida de echo "abc".

En cambio: (echo "abc"; cat 1.txt) > 2.txt escribirá la salida de ambos comandos en 2.txt.

muclux
fuente
Esta respuesta puede mejorarse explicando cómo funciona la alternativa sugerida.
Bob
1

En cualquier shell POSIX, puede usar la sustitución de comandos para usar cat filecomo entrada para echo:

echo $(cat file1.txt) "This Too"

En Bash puede usar la sustitución de procesos y usar echo como otro "archivo" para cat, como en:

cat file1.txt <(echo This Too)

y luego canalice o redirija la salida como mejor le parezca.

Como dice cualquier otra respuesta, cat ignora stdin si tiene que ver un archivo. (También me gustan las respuestas de Daniel y mvw, +1 para ellas)

Xen2050
fuente
1
Esta respuesta puede mejorarse explicando por qué el intento original del OP no funciona (y, por lo tanto, por qué esto es necesario).
Bob
1
La <(command)construcción es una extensión de bash. No es POSIX, por lo que no puede confiar en él en scripts con los que se supone que deben ejecutarse /bin/sh.
Rhialto apoya a Mónica el
0

Solo una suposición, pero parece que tienes un proceso repetible, que es un buen candidato para un alias o una función. Los alias suelen ser atajos para invocar comandos bash, como la abreviatura, en una sola secuencia de entrada como argumento / s.

alias hg="history | grep"

Sin embargo, en este caso, una función sería más legible, ya que está combinando múltiples flujos de entrada discretos (2), así como múltiples comandos bash. Tiene dos argumentos, el primero es una cadena y el otro una ruta de archivo. Al final, desea que el resultado se escriba en la secuencia de salida estándar.

Desde un indicador de CLI, escriba esto:

# ecat()        
{
echo ${1}
cat ${2}
}

Su función se llama ecat, que es memorable.

Ahora puedes invocar como

ecat "abc" 1.txt

Para agregar, simplemente proporcione un destino de salida diferente para stdout:

ecat "abc" 1.txt >> 2.txt

El operador de redireccionamiento anexar '>>' agregará la salida al final del archivo especificado.

Si le gusta, anexe a su archivo ~ / .bashrc para reutilizarlo.

declare -f ecat >> ~/.bashrc

Eso también significa que puede decorar, etc., dentro de la definición de su función.

También es una buena idea proteger los archivos para que no se sobrescriban agregando esto a su ~ / .bashrc

set noclobber
FrDarryl
fuente
2
Para que su función se comporte correctamente, debe usar "$1"y "$2". En este contexto, las llaves no hacen ningún bien. Ver ${name}no significa lo que usted cree ... .
G-Man dice 'restablecer a Monica' el
1
¿Cómo noclobberresponde la sugerencia a la pregunta en cuestión? (Tampoco estoy muy convencido de que sea un buen consejo: modificar el comportamiento global tiende a romper los scripts / consejos / prácticas creados con los valores predeterminados en mente).
Charles Duffy el
0

El siguiente código también funcionará:

echo abc >> 1.txt && cat 1.txt > 2.txt

La salida de echo abc se agregará a 1.txt con >> Después de eso, && le indicará que ejecute el siguiente conjunto de comandos que tomará 1.txt y luego lo enviará a 2.txt . Básicamente, agrega la salida del primer comando a 1.txt y luego envía la salida de 1.txt a 2.txt.

Si desea que el abc aparezca primero, puede usar el siguiente código:

echo abc >> 2.txt && cat 1.txt >> 2.txt
Nasir Riley
fuente
1
Esto (1) se colocará abcen la parte inferior de 2.txt; la pregunta lo quiere en la cima. (2)  modificar el 1.txtarchivo; Esto es inaceptable.
G-Man dice 'reinstalar a Monica' el
¿Dónde dice eso? Ringger81 nunca especificó dónde en 2.txt quería que abc apareciera. Estás asumiendo cosas que la pregunta nunca dice.
Nasir Riley el
(1) OK, planteas un punto válido en el n. ° 1. Si bien la pregunta menciona "salida de echo" antes de "contenido de un archivo" en el texto, y luego pone el echoantes caten el comando de ejemplo, supongo que nunca, explícitamente , dice que quiere la salida de echo antes del contenido del archivo de entrada. Parece que la mayoría de la gente lo interpretó de esa manera. (2)  1.txtes un archivo de entrada. La pregunta no dice nada sobre la modificación 1.txt. El hecho de que los archivos de entrada no deben modificarse es evidente.
G-Man dice 'restablecer a Mónica' el
Puedo entender su punto sobre no modificar el archivo imput. Mi segundo código logrará el efecto deseado sin hacerlo.
Nasir Riley
1
Abrir un archivo, agregarlo, cerrarlo , abrirlo nuevamente, agregarlo nuevamente ... ¿por qué hacer eso en lugar de simplemente abrirlo una vez y mantener la redirección en su lugar para ambas operaciones?
Charles Duffy el