2012-03-23 13 views
25

que a menudo utilizan tubos en bash, por ejemplo .:¿Cuál es una explicación simple de cómo funcionan las tuberías en BASH?

dmesg | less 

Aunque sé lo que este salidas, se necesita dmesg y me permite desplazarse por éste con less, no entiendo lo que el | está haciendo. ¿Es simplemente lo opuesto a >?

  • ¿Hay una explicación simple o metafórica de lo que | hace?
  • ¿Qué sucede cuando se usan varias tuberías en una sola línea?
  • ¿El comportamiento de las tuberías es coherente en todas partes en un script de BASH?

Respuesta

2

El operador de tubería toma la salida del primer comando, y lo 'canaliza' al segundo conectando stdin y stdout. En su ejemplo, en lugar de que la salida del comando dmesg vaya a stdout (y lo arroje a la consola), va directamente a su siguiente comando.

+1

Las tuberías no pasan la salida como parámetro. Las tuberías conectan STDOUT a STDIN. Algunos comandos deben ser instruidos específicamente para mirar STDIN (generalmente dando un guión en lugar de un nombre de archivo) antes de que puedan ser utilizados en las tuberías. – quanticle

+0

Muy bien, gracias por la corrección! Actualicé mi respuesta. – franka

+0

Es muy importante tener en cuenta que también lo transmite. El proceso de la derecha no necesita esperar a que termine el proceso de la izquierda antes de que pueda comenzar a funcionar. Entonces cosas como 'sí | rm -r * 'como alternativa al trabajo' rm -rf * 'aunque sí nunca termina de ejecutar – Paulpro

39

Un tubo Unix conecta el descriptor de archivo STDOUT (salida estándar) del primer proceso al STDIN (entrada estándar) del segundo. Lo que sucede entonces es que cuando el primer proceso escribe en su STDOUT, ese resultado puede leerse inmediatamente (desde STDIN) por el segundo proceso.

El uso de múltiples tuberías no es diferente de usar una sola tubería. Cada tubería es independiente y simplemente vincula STDOUT y STDIN de los procesos adyacentes.

Su tercera pregunta es un poco ambigua. Sí, las tuberías, como tales, son consistentes en todas partes en un script bash. Sin embargo, el carácter de tubería | puede representar cosas diferentes. La tubería doble (||) representa el operador "or", por ejemplo.

+18

¡Tenga en cuenta la palabra "__inmediatamente__"! Señalo esto porque nosotros que usamos Bash para guiones casuales, pensamos en nuestros comandos como sincrónicos, nuestros guiones como completamente secuenciales. Esperamos que las tuberías ejecuten el comando de la izquierda y pasen su salida al siguiente comando. Pero las tuberías usan bifurcación, y _los comandos se ejecutan en realidad en paralelo_. Para muchos comandos, este hecho es funcionalmente inconsecuente, pero [a veces importa] (http://stackoverflow.com/q/6893714/445295). Por ejemplo, vea la salida de: 'ps | gato'. –

2
  • | coloca a la salida estándar del comando en el lado izquierdo de la STDIN del mando del lado derecho.

  • Si usa múltiples tuberías, es solo una cadena de tuberías. La salida de los primeros comandos se establece en la entrada de segundos comandos. La segunda salida de comandos se establece en la siguiente entrada de comandos. Etc.

  • Está disponible en todos los intérpretes de comandos basados ​​en Linux/viudas.

12

Cada proceso estándar en Unix tiene al menos tres descriptores de fichero, que son algo así como interfaces de:

  • salida estándar, que es el lugar donde el proceso imprime sus datos (la mayoría de las veces la consola, es decir, su pantalla o terminal).
  • Entrada estándar, que es el lugar de donde obtiene sus datos (la mayoría de las veces puede ser algo similar a su teclado).
  • Error estándar, que es el lugar donde van los errores y, a veces, otros datos fuera de banda. No es interesante en este momento porque las tuberías normalmente no se ocupan de eso.

El tubo conecta la salida estándar del proceso de la izquierda para la entrada estándar del proceso de la derecha. Puedes pensar que es un programa dedicado que se encarga de copiar todo lo que un programa imprime y de alimentarlo al siguiente programa (el que está después del símbolo de la tubería). No es exactamente eso, pero es una analogía suficientemente adecuada.

Cada tubería funciona exactamente en dos cosas: la salida estándar viene de la izquierda y la secuencia de entrada esperada a la derecha. Cada uno de ellos se puede unir a un solo proceso u otro bit de la tubería, que es el caso en una línea de comando de múltiples tubos. Pero eso no es relevante para la operación real de la tubería; cada tubería hace lo propio.

El operador de redirección (>) hace algo relacionado, pero más simple: por defecto, envía la salida estándar de un proceso directamente a un archivo. Como puede ver, no es lo opuesto a una tubería, sino que en realidad es complementario. Lo contrario de > es sorprendentemente <, que toma el contenido de un archivo y lo envía a la entrada estándar de un proceso (piénselo como un programa que lee un byte de archivo por byte y lo escribe en un proceso para usted).

5

Una tubería toma la salida de un proceso, por salida me refiero a la salida estándar (stdout en UNIX) y la pasa a la entrada estándar (stdin) de otro proceso. No es lo opuesto al simple redireccionamiento a la derecha > cuyo objetivo es redirigir una salida a otra salida.

Por ejemplo, tome el comando echo en Linux que simplemente está imprimiendo una cadena pasada en parámetro en la salida estándar. Si utiliza una redirección simple como:

echo "Hello world" > helloworld.txt 

la cáscara volverá a dirigir la salida normal prevista inicialmente para estar en la salida estándar e imprimirla directamente en el archivo helloworld.txt.

Ahora, tome este ejemplo que implica la tubería:

ls -l | grep helloworld.txt

La salida estándar del comando ls se superará en la entrada de grep, entonces, ¿cómo funciona esto?

Los programas como grep cuando se usan sin argumentos son simplemente leer y esperar a que se transmita algo en su entrada estándar (stdin). Cuando atrapan algo, como la salida del comando ls, grep actúa normalmente al encontrar una ocurrencia de lo que estás buscando.

1

Si usted trata a cada comando UNIX como un módulo independiente,
pero es necesario que se comuniquen entre sí de texto utilizando como interfaz consistente,
cómo se puede hacer esto?

cmd      input     output 

echo "foobar"    string     "foobar" 
cat "somefile.txt"  file      *string inside the file* 
grep "pattern" "a.txt" pattern, input file  *matched string* 

Se puede decir | es una metáfora para pasar el testigo en un maratón de relevos.
¡Tiene incluso forma de uno!
cat -> echo -> less -> awk -> perl es análogo a cat | echo | less | awk | perl.

cat "somefile.txt" | echo
cat pasar su salida de echo de usar.

¿Qué sucede cuando hay más de una entrada?
cat "somefile.txt" | grep "pattern"
Hay una regla implícita que dice "pasarlo como archivo de entrada en lugar de patrón" para grep.
Desarrollarás lentamente el ojo para saber qué parámetro es el que por experiencia.

1

Las tuberías son muy simples como esta.

Tiene la salida de un comando. Puede proporcionar esta salida como la entrada a otro comando usando pipe. Puede canalizar tantos comandos como desee.

ex: ls | grep my | archivos grep

Esto primero enumera los archivos en el directorio de trabajo. Esta salida se comprueba mediante el comando grep para la palabra "mi". El resultado de esto ahora está en el segundo comando grep que finalmente busca la palabra "archivos". Eso es.

9

En Linux (y Unix en general) cada proceso tiene tres descriptores de archivo por defecto:

  1. fd # 0 representa la entrada estándar del proceso
  2. fd # 1 representa la salida estándar del proceso
  3. fd # 2 representa la salida de error estándar del proceso

Normalmente, cuando se ejecuta un programa sencillo estos descriptores de archivo por defecto están configurados de la siguiente manera:

  1. de entrada por defecto se lee desde el teclado
  2. de salida estándar está configurado para ser el monitor
  3. Error estándar está configurado para ser el monitor también

Bash proporciona varios operadores para cambiar este comportamiento (Eche un vistazo a los operadores>, >> y < por ejemplo). Por lo tanto, puede redirigir la salida a algo que no sea la salida estándar o leer su entrada de otra secuencia diferente al teclado. Especialmente interesante es el caso cuando dos programas son que colaboran con de tal manera que uno utiliza la salida del otro como su entrada. Para facilitar esta colaboración, Bash proporciona el operador de tubería |. Tenga en cuenta el uso de la colaboración en lugar de encadenando. Evité el uso de este término ya que, de hecho, una tubería no es secuencial. Una línea de comandos normal con tubos tiene el siguiente aspecto:

> program_1 | program_2 | ... | program_n 

La línea de comandos anterior es un poco engañosa: el usuario podría pensar que program_2 toma su entrada una vez que el program_1 ha terminado su ejecución, lo cual no es correcto.De hecho, lo que Bash hace es lanzar ALL los programas en paralelo y configura las salidas de entrada en consecuencia para que cada programa obtenga su entrada del anterior y entregue su salida al siguiente (en el orden establecido de la línea de comando).

A continuación se muestra un ejemplo simple de Creating pipe in C para crear un conducto entre un proceso primario y otro secundario. La parte importante es la llamada a la tubería() y cómo el padre cierra fd 1 (lado de escritura) y cómo el niño cierra fd 1 (lado de escritura). Tenga en cuenta que la tubería es un canal de comunicación unidireccional. Por lo tanto, los datos solo pueden fluir en una dirección: fd 1 hacia fd [0]. Para obtener más información, consulte la página de manual de pipe().

#include <stdio.h> 
#include <unistd.h> 
#include <sys/types.h> 

int main(void) 
{ 
    int  fd[2], nbytes; 
    pid_t childpid; 
    char string[] = "Hello, world!\n"; 
    char readbuffer[80]; 

    pipe(fd); 

    if((childpid = fork()) == -1) 
    { 
      perror("fork"); 
      exit(1); 
    } 

    if(childpid == 0) 
    { 
      /* Child process closes up input side of pipe */ 
      close(fd[0]); 

      /* Send "string" through the output side of pipe */ 
      write(fd[1], string, (strlen(string)+1)); 
      exit(0); 
    } 
    else 
    { 
      /* Parent process closes up output side of pipe */ 
      close(fd[1]); 

      /* Read in a string from the pipe */ 
      nbytes = read(fd[0], readbuffer, sizeof(readbuffer)); 
      printf("Received string: %s", readbuffer); 
    } 

    return(0); 
} 

Por último, pero no menos importante, cuando se tiene una línea de comandos en la forma:

> program_1 | program_2 | program_3 

El código de retorno de la totalidad de las líneas se establece en el último comando . En este caso program_3. Si desea obtener un código de retorno intermedio, debe configurar el pipefail o obtenerlo del PIPESTATUS.

Cuestiones relacionadas