Salida diferida de dos programas sin archivos temporales


Respuestas:


211

Use <(command)para pasar la salida de un comando a otro programa como si fuera un nombre de archivo. Bash canaliza la salida del programa a una canalización y pasa un nombre de archivo como /dev/fd/63al comando externo.

diff <(./a) <(./b)

Del mismo modo, puede usar >(command)si desea canalizar algo en un comando.

Esto se llama "Sustitución de proceso" en la página de manual de Bash.


1
Un inconveniente a tener en cuenta es que si ./a o ./b falla, la persona que llama no lo descubrirá.
Alexander Pogrebnyak

55
El OP etiquetó la pregunta bash, pero para el registro, esto no funciona en ningún otro shell. Es una extensión bash del estándar de utilidad Posix.
DigitalRoss

55
Probé esta solución con un programa Java y dio este mensaje: -bash: syntax error near unexpected token ('. Lo intenté de nuevo sin paréntesis y lo conseguí -bash: java: No such file or directory. ¿No funciona si el comando tiene parámetros?
styfle

1
@DigitalRoss: la solución se puede extender a otros shells utilizando un alias. En tcsh, la siguiente fealdad funciona: alias diffcmd bash -c \'diff \<\(sh -c \!:1\) \<\( sh -c \!:2 \)\'. (Entonces, por ejemplo: diffcmd "ls" "ls -a").
Paul Lynch

Para cualquiera que deambule fuera de Google, esto también funciona bajo zsh. (También, si necesita de entrada de alimentación en algo que se pide fseek, ofertas zsh =(./a)que se pueden utilizar de forma idéntica a <(./a), pero utiliza un archivo temporal bajo el capó, que zsh eliminará para usted.)
ssokolow

26

Agregando a ambas respuestas, si desea ver una comparación lado a lado, use vimdiff:

vimdiff <(./a) <(./b)

Algo como esto:

ingrese la descripción de la imagen aquí


vimdiffcrea vistas de comparación de diferencias hermosas, inteligentes e interactivas. Parece venir con el vimpaquete en la mayoría de los sistemas.
Tim Visée

vimdifftambién muestra no solo la línea que difiere sino también el fragmento de texto específico que difiere.
Anton Tarasenko


15

Para cualquier persona curiosa, así es como se realiza la sustitución del proceso al usar el shell Fish :

Intento:

diff <(./a) <(./b)

Pez:

diff (./a | psub) (./b | psub)

Desafortunadamente, la implementación en peces es actualmente deficiente ; fish se colgará o usará un archivo temporal en el disco. Tampoco puede usar psub para la salida de su comando.


Actualmente, esto no funciona correctamente en peces. Si la salida de los programas es mayor que un BUFSIZ, el comando se bloqueará. (o fish en realidad solo usará un archivo temporal en el disco)
Evan Benn

7

Agregar un poco más a las respuestas ya buenas (¡me ayudó!):

El comando dockerenvía su ayuda a STD_ERR(es decir, descriptor de archivo 2)

Quería ver si docker attachy docker attach --helpdaba el mismo resultado

$ docker attach

$ docker attach --help

Después de escribir esos dos comandos, hice lo siguiente:

$ diff <(!-2 2>&1) <(!! 2>&1)

!! es lo mismo que! -1, lo que significa ejecutar el comando 1 antes de este: el último comando

! -2 significa ejecutar el comando dos antes de este

2> & 1 significa enviar la salida file_descriptor 2 (STD_ERR) al mismo lugar que la salida file_descriptor 1 (STD_OUT)

Espero que esto haya sido de alguna utilidad.


0

Para zsh, el uso =(command)crea automáticamente un archivo temporal y lo reemplaza =(command)con la ruta del archivo en sí. Con la sustitución de proceso normal, $(command)se reemplaza con la salida del comando.

Esta función zsh es muy útil y se puede usar para comparar la salida de dos comandos con una herramienta diff, por ejemplo, Beyond Compare:

bcomp  =(ulimit -Sa | sort) =(ulimit -Ha | sort)

Para Beyond Compare, tenga en cuenta que debe usar bcomplo anterior (en lugar de bcompare) desde que bcompinicia la comparación y espera a que se complete. Si lo usa bcompare, inicia la comparación e inmediatamente se cierra debido a que los archivos temporales creados para almacenar la salida de los comandos desaparecen.

Lea más aquí: http://zsh.sourceforge.net/Intro/intro_7.html

También tenga en cuenta esto:

Tenga en cuenta que el shell crea un archivo temporal y lo elimina cuando finaliza el comando.

y el siguiente, que es la diferencia entre $(...)y =(...):

Si lee la página de manual de zsh, puede notar que <(...) es otra forma de sustitución de proceso que es similar a = (...). Hay una diferencia importante entre los dos. En el caso <(...), el shell crea una tubería con nombre (FIFO) en lugar de un archivo. Esto es mejor, ya que no llena el sistema de archivos; pero no funciona en todos los casos. De hecho, si hubiéramos reemplazado = (...) con <(...) en los ejemplos anteriores, todos habrían dejado de funcionar, excepto fgrep -f <(...). No puede editar una tubería o abrirla como una carpeta de correo; fgrep, sin embargo, no tiene problemas para leer una lista de palabras de una tubería. Quizás se pregunte por qué la barra diff <(foo) no funciona, ya que foo | trabajos de barra diferencial; esto se debe a que diff crea un archivo temporal si nota que uno de sus argumentos es -, y luego copia su entrada estándar al archivo temporal.

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.