¿Cuál es una explicación sencilla de cómo funcionan las tuberías en Bash?

Resuelto Village asked hace 12 años • 0 respuestas

A menudo uso tuberías en Bash, por ejemplo:

dmesg | less

Aunque sé lo que esto genera, lo toma dmesgy me permite desplazarme por él less, no entiendo qué |está haciendo. ¿Es simplemente lo contrario de >?

  • ¿Existe una explicación simple o metafórica para lo que |hace?
  • ¿Qué sucede cuando se utilizan varios tubos en una sola línea?
  • ¿El comportamiento de las tuberías es consistente en todos los lugares donde aparece en un script Bash?
Village avatar Mar 23 '12 11:03 Village
Aceptado

Una tubería 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, el segundo proceso puede leer esa salida inmediatamente (desde STDIN).

Usar varias tuberías no es diferente a usar una sola tubería. Cada tubería es independiente y simplemente vincula STDOUT y STDIN de los procesos adyacentes.

Tu 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. Doble barra vertical ( ||), representa el operador "o", por ejemplo.

quanticle avatar Mar 23 '2012 04:03 quanticle

En Linux (y Unix en general) cada proceso tiene tres descriptores de archivos predeterminados:

  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 ejecuta un programa simple, estos descriptores de archivos se configuran de forma predeterminada de la siguiente manera:

  1. la entrada predeterminada se lee desde el teclado
  2. La salida estándar está configurada para ser el monitor.
  3. El 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 desde otra secuencia diferente al teclado. Es especialmente interesante el caso en el que dos programas colaboran de tal manera que uno utiliza la salida del otro como entrada. Para facilitar esta colaboración, Bash proporciona el operador de tubería |. Tenga en cuenta el uso de colaboración en lugar de encadenamiento . Evité el uso de este término ya que, de hecho, una tubería no es secuencial . Una línea de comando normal con tuberías tiene el siguiente aspecto:

    > program_1 | program_2 | ... | program_n

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

A continuación se muestra un ejemplo simple de Creación de una tubería en C sobre cómo crear una tubería entre un proceso principal y un proceso secundario. La parte importante es la llamada a pipe() 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 tanto, los datos sólo pueden fluir en una dirección: fd 1 hacia fd[0]. Para obtener más información, consulte la página del 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 tienes una línea de comando en el formulario:

> program_1 | program_2 | program_3

El código de retorno de toda la línea se establece en el último comando. En este caso programa_3. Si desea obtener un código de retorno intermedio, debe configurar pipefail u obtenerlo de PIPESTATUS .

rkachach avatar Oct 05 '2015 10:10 rkachach

En resumen, como se describe, hay tres descriptores de archivos "especiales" clave que se deben tener en cuenta. El shell envía por defecto el teclado stdiny envía stdouty stderra la pantalla:

stdin, stdout, stderr

Una tubería es solo una conveniencia de shell que conecta el stdoutproceso de un proceso directamente al stdinsiguiente:

tubería simple

Hay muchas sutilezas sobre cómo funciona esto; por ejemplo, stderres posible que la transmisión no se transmita como se esperaría, como se muestra a continuación:

stderr y redirección

He pasado bastante tiempo intentando escribir una explicación detallada pero amigable para principiantes sobre las canalizaciones en Bash. El contenido completo está en:

https://efectivo-shell.com/part-2-core-skills/thinking-in-pipelines/

Dave Kerr avatar Sep 20 '2020 14:09 Dave Kerr

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

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

La tubería conecta la salida estándar del proceso de la izquierda con la entrada estándar del proceso de la derecha. Puede considerarlo como un programa dedicado que se encarga de copiar todo lo que imprime un programa y enviarlo al siguiente programa (el que está después del símbolo de la tubería). No es exactamente eso, pero es una analogía bastante adecuada.

Cada tubería opera exactamente con dos cosas: la salida estándar que viene de su izquierda y el flujo de entrada esperado a su derecha. Cada uno de ellos podría adjuntarse a un solo proceso u otra parte de la tubería, como es el caso en una línea de comando de múltiples tuberías. Pero eso no es relevante para el funcionamiento real de la tubería; cada pipa hace lo suyo.

El operador de redirección ( >) hace algo relacionado, pero más simple: de forma predeterminada envía la salida estándar de un proceso directamente a un archivo. Como puedes ver no es lo opuesto a una pipa, sino complementaria. Lo opuesto a , >como era de esperar <, toma el contenido de un archivo y lo envía a la entrada estándar de un proceso (piense en ello como un programa que lee un archivo byte a byte y lo escribe en un proceso por usted).

Eduardo Ivanec avatar Mar 23 '2012 04:03 Eduardo Ivanec

Una tubería toma la salida de un proceso, por salida me refiero a la salida estándar ( stdouten UNIX) y la pasa a la entrada estándar (stdin)de otro proceso. No es lo opuesto a la simple redirección derecha >cuyo propósito es redirigir una salida a otra salida.

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

echo "Hello world" > helloworld.txt

el shell redirigirá la salida normal inicialmente prevista para estar en la salida estándar y la imprimirá directamente en el archivo helloworld.txt.

Ahora, tomemos este ejemplo que involucra la tubería:

ls -l | grep holamundo.txt

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

Los programas, como grepcuando se utilizan sin ningún argumento, simplemente leen y esperan que se pase algo en su entrada estándar (stdin). Cuando detectan algo, como la salida del comando ls, grep actúa normalmente encontrando una ocurrencia de lo que estás buscando.

Halim Qarroum avatar Mar 23 '2012 04:03 Halim Qarroum