Pipe se utiliza para pasar la salida a otro programa o utilidad .
Redirect se utiliza para pasar la salida a un archivo o secuencia .
Ejemplo: thing1 > thing2
vsthing1 | thing2
thing1 > thing2
- Su shell ejecutará el programa llamado
thing1
- Todo lo que
thing1
salga se colocará en un archivo llamado thing2
. (Nota: si thing2
existe, se sobrescribirá)
Si desea pasar la salida del programa thing1
a un programa llamado thing2
, puede hacer lo siguiente:
thing1 > temp_file && thing2 < temp_file
Cuál debería
- ejecutar programa llamado
thing1
- guardar la salida en un archivo llamado
temp_file
- ejecute el programa llamado
thing2
, pretendiendo que la persona en el teclado escribió el contenido temp_file
como entrada.
Sin embargo, eso es torpe, por lo que hicieron tuberías como una forma más simple de hacerlo. thing1 | thing2
hace lo mismo quething1 > temp_file && thing2 < temp_file
EDITAR para proporcionar más detalles a la pregunta en el comentario:
Si se >
trata de ser "pasar al programa" y "escribir en el archivo", podría causar problemas en ambas direcciones.
Primer ejemplo: está intentando escribir en un archivo. Ya existe un archivo con ese nombre que desea sobrescribir. Sin embargo, el archivo es ejecutable. Presumiblemente, intentaría ejecutar este archivo, pasando la entrada. Tendría que hacer algo como escribir la salida en un nuevo nombre de archivo, luego cambiar el nombre del archivo.
Segundo ejemplo: como señaló Florian Diesch, ¿qué pasa si hay otro comando en otra parte del sistema con el mismo nombre (que está en la ruta de ejecución). Si pretendía hacer un archivo con ese nombre en su carpeta actual, estaría atascado.
En tercer lugar: si escribe incorrectamente un comando, no le advertirá que el comando no existe. En este momento, si escribe, ls | gerp log.txt
se lo dirá bash: gerp: command not found
. Si >
significaba ambos, simplemente crearía un nuevo archivo para usted (luego advierta que no sabe qué hacer log.txt
).
thing1 > temp_file && thing2 < temp_file
hacer más fácil con las tuberías. Pero, ¿por qué no reutilizar el>
operador para hacer esto, por ejemplo,thing1 > thing2
para comandosthing1
ything2
? ¿Por qué un operador extra|
?less
, por ejemplo?thing | less
ything > less
son perfectamente diferentes, ya que hacen cosas diferentes. Lo que propones crearía una ambigüedad.tee
comando hace algo diferente.tee
escribe la salida tanto en la pantalla (stdout
) como en el archivo. Redirect solo hace el archivo.Si el significado de
foo > bar
depende de si hay un comando llamadobar
que haría que el uso de la redirección sea mucho más difícil y más propenso a errores: cada vez que quiero redirigir a un archivo, primero tuve que verificar si hay un comando llamado como mi archivo de destino.fuente
bar
en un directorio que es parte de su$PATH
variable env. Si estás en algo como / bin, entonces ot podría ser un problema. Pero incluso entonces,bar
tendría que tener un conjunto de permisos ejecutable, de modo que el shell no solo busque un ejecutable,bar
sino que realmente pueda ejecutarlo. Y si la preocupación es sobrescribir el archivo existente, lanoclober
opción de shell debería evitar sobrescribir los archivos existentes en las redirecciones.Del Manual de administración del sistema Unix y Linux:
Entonces mi interpretación es: si es comando a comando, use una tubería. Si sale ao desde un archivo, use la redirección.
fuente
Hay una diferencia vital entre los dos operadores:
ls > log.txt
-> Este comando envía la salida al archivo log.txt.ls | grep file.txt
-> Este comando envía la salida del comando ls al grep mediante el uso de pipe (|
), y el comando grep busca file.txt en la entrada proporcionada por el comando anterior.Si tuviera que realizar la misma tarea usando el primer escenario, entonces sería:
Entonces, una tubería (con
|
) se usa para enviar la salida a otro comando, mientras que la redirección (con>
) se usa para redirigir la salida a algún archivo.fuente
Hay una gran diferencia sintáctica entre los dos:
Se puede pensar en redirecciones como este:
cat [<infile] [>outfile]
. Esto implica que el orden no importa:cat <infile >outfile
es lo mismo quecat >outfile <infile
. Incluso puede mezclar redirecciones con otros argumentos:cat >outfile <infile -b
ycat <infile -b >outfile
ambos están perfectamente bien. También se puede encadenar más de una entrada o salida (entradas serán leídos secuencialmente y toda la salida se escribirá en cada archivo de salida):cat >outfile1 >outfile2 <infile1 <infile2
. El objetivo o la fuente de una redirección puede ser un nombre de archivo o el nombre de una secuencia (como & 1, al menos en bash).Pero las tuberías separan totalmente un comando de otro comando, no puede mezclarlos con argumentos:
La tubería toma todo lo escrito en la salida estándar del comando1 y lo envía a la entrada estándar del comando2.
También puede combinar tuberías y redireccionamiento. Por ejemplo:
El primero
cat
leerá líneas desde el archivo, luego simultáneamente escribirá cada línea para archivar y la enviará al segundocat
.En el segundo
cat
, la entrada estándar primero lee desde la tubería (el contenido del archivo), luego lee desde infile2, escribiendo cada línea en outfile2. Después de ejecutar esto, outfile será una copia de infile, y outfile2 contendrá infile seguido de infile2.Finalmente, en realidad haces algo muy similar a tu ejemplo usando la redirección "here string" (solo bash family) y backticks:
dará el mismo resultado que
Pero creo que la versión de redirección primero leerá toda la salida de ls en un búfer (en memoria), y luego alimentará ese búfer para agrupar una línea a la vez, mientras que la versión canalizada tomará cada línea de ls a medida que emerge, y pasa esa línea a grep.
fuente
echo yes 1>&2 2>/tmp/blah; wc -l /tmp/blah; echo yes 2>/tmp/blah 1>&2; wc -l /tmp/blah
además, la redirección a un archivo solo usará la última redirección.echo yes >/tmp/blah >/tmp/blah2
solo escribirá a/tmp/blah2
.Nota: La respuesta refleja mi propia comprensión de estos mecanismos actualizados, acumulados durante la investigación y la lectura de las respuestas de los pares en este sitio y en unix.stackexchange.com , y se actualizará a medida que pase el tiempo. No dude en hacer preguntas o sugerir mejoras en los comentarios. También le sugiero que intente ver cómo funcionan las llamadas al sistema en shell con el
strace
comando. Además, no se deje intimidar por la noción de elementos internos o syscalls: no tiene que saberlos ni poder usarlos para comprender cómo funciona Shell, pero definitivamente ayudan a comprender.TL; DR
|
las tuberías no están asociadas con una entrada en el disco, por lo tanto, no tienen un número de inodo del sistema de archivos de disco (pero sí tienen un inodo en el sistema de archivos virtual de pipefs en el espacio del kernel), pero las redirecciones a menudo involucran archivos, que tienen entradas de disco y, por lo tanto, tienen el correspondiente inodolseek()
capaces, por lo que los comandos no pueden leer algunos datos y luego retroceder, pero cuando se redirige>
o<
generalmente es un archivolseek()
capaz de objetos, los comandos pueden navegar como quieran.dup2()
syscalls debajo del capó para proporcionar copias de descriptores de archivos, donde ocurre el flujo real de datos.exec
comando incorporado (vea esto y esto ), por lo que si lo hace,exec > output.txt
todos los comandos escribirán aoutput.txt
partir de ese momento.|
las tuberías se aplican solo para el comando actual (lo que significa un comando simple o comoseq 5 | (head -n1; head -n2)
comandos de subshell o compuestos.Cuando se realiza la redirección en los archivos, cosas como
echo "TEST" > file
yecho "TEST" >> file
ambos usanopen()
syscall en ese archivo ( ver también ) y obtienen un descriptor de archivo para pasarlodup2()
. Las tuberías|
solo usanpipe()
ydup2()
syscall.En lo que respecta a los comandos que se ejecutan, las canalizaciones y la redirección no son más que descriptores de archivos: objetos en forma de archivo, en los que pueden escribir a ciegas, o manipularlos internamente (lo que puede producir comportamientos inesperados;
apt
por ejemplo, tiende a ni siquiera escribir en stdout si sabe que hay redirección).Introducción
Para entender cómo difieren estos dos mecanismos, es necesario comprender sus propiedades esenciales, la historia detrás de los dos y sus raíces en el lenguaje de programación C. De hecho, saber qué son los descriptores de archivos, y cómo funcionan las llamadas al sistema
dup2()
y tambiénpipe()
es esenciallseek()
. Shell pretende ser una forma de hacer que estos mecanismos sean abstractos para el usuario, pero cavar más profundo que la abstracción ayuda a comprender la verdadera naturaleza del comportamiento de shell.Los orígenes de las redirecciones y tuberías
Según el artículo de Dennis Ritche, Petroglifos proféticos , las tuberías se originaron en un memorando interno de 1964 de Malcolm Douglas McIlroy , cuando trabajaban en el sistema operativo Multics . Citar:
Lo que es evidente es que en ese momento los programas eran capaces de escribir en el disco, sin embargo, eso era ineficiente si la salida era grande. Para citar la explicación de Brian Kernighan en el video de Unix Pipeline :
Así, la diferencia conceptual es evidente: las tuberías son un mecanismo para hacer que los programas se comuniquen entre sí. Redirecciones: son una forma de escribir en el archivo a nivel básico. En ambos casos, Shell hace que estas dos cosas sean fáciles, pero debajo del capó, están sucediendo muchas cosas.
Profundizando: syscalls y funcionamiento interno del shell
Comenzamos con la noción de descriptor de archivo . Los descriptores de archivo describen básicamente un archivo abierto (ya sea un archivo en el disco, en la memoria o un archivo anónimo), que está representado por un número entero. Los dos flujos de datos estándar (stdin, stdout, stderr) son descriptores de archivo 0,1 y 2 respectivamente. De dónde vienen ? Bueno, en los comandos de shell los descriptores de archivo se heredan de su padre - shell. Y es cierto en general para todos los procesos: el proceso hijo hereda los descriptores de archivo de los padres. Para los demonios , es común cerrar todos los descriptores de archivos heredados y / o redirigir a otros lugares.
De vuelta a la redirección. Que es realmente Es un mecanismo que le dice al shell que prepare los descriptores de archivo para el comando (porque el redireccionamiento lo realiza el shell antes de que se ejecute el comando) y los señala donde el usuario sugirió. La definición estándar de redirección de salida es
Que
[n]
existe el número de descriptor de archivo. Cuando hacesecho "Something" > /dev/null
el número 1 está implícito allí, yecho 2> /dev/null
.Debajo del capó, esto se hace duplicando el descriptor de archivo a través de la
dup2()
llamada al sistema. Vamos a tomardf > /dev/null
. El shell creará un proceso secundario donde sedf
ejecuta, pero antes de eso se abrirá/dev/null
como descriptor de archivo # 3, ydup2(3,1)
se emitirá, lo que hace una copia del descriptor de archivo 3 y la copia será 1. Usted sabe cómo tiene dos archivosfile1.txt
yfile2.txt
, y cuando lo hagacp file1.txt file2.txt
, tendrá dos mismos archivos, pero puede manipularlos de forma independiente. Eso es lo mismo que sucede aquí. A menudo, puede ver que antes de ejecutar,bash
deberádup(1,10)
hacer una copia del descriptor de archivo # 1 que esstdout
(y esa copia será fd # 10) para restaurarla más tarde. Es importante tener en cuenta que cuando se consideran los comandos integrados(que son parte del shell en sí y no tienen ningún archivo en ningún/bin
otro lado) o comandos simples en un shell no interactivo , el shell no crea un proceso hijo.Y luego tenemos cosas como
[n]>&[m]
y[n]&<[m]
. Esto es duplicar los descriptores de archivos, que el mismo mecanismo quedup2()
solo ahora tiene la sintaxis de shell, convenientemente disponible para el usuario.Una de las cosas importantes a tener en cuenta sobre la redirección es que su orden no es fijo, pero es importante para la forma en que Shell interpreta lo que el usuario quiere. Compare lo siguiente:
El uso práctico de estos en scripts de shell puede ser versátil:
y muchos otros.
Fontanería con
pipe()
ydup2()
Entonces, ¿cómo se crean las tuberías? A través de
pipe()
syscall , que tomará como entrada una matriz (también conocida como lista) llamadapipefd
de dos elementos de tipoint
(entero). Esos dos enteros son descriptores de archivo. Elpipefd[0]
será el fin de leer de la tubería ypipefd[1]
será el final de escritura. Entoncesdf | grep 'foo'
,grep
obtendrá una copia depipefd[0]
ydf
obtendrá una copia depipefd[1]
. Pero cómo ? Por supuesto, con la magia dedup2()
syscall. Endf
nuestro ejemplo, digamos quepipefd[1]
tiene el n. ° 4, por lo que el shell creará un hijo, hacerdup2(4,1)
(¿recuerda micp
ejemplo?) Y luego hacerexecve()
para ejecutar realmentedf
. Naturalmente,df
heredará el descriptor de archivo n. ° 1, pero no se dará cuenta de que ya no está apuntando a la terminal, sino en realidad fd n. ° 4, que en realidad es el extremo de escritura de la tubería. Naturalmente, ocurrirá lo mismogrep 'foo'
excepto con diferentes números de descriptores de archivo.Ahora, una pregunta interesante: ¿podríamos hacer tuberías que redirijan fd # 2 también, no solo fd # 1? Sí, de hecho eso es lo que
|&
hace en bash. El estándar POSIX requiere un lenguaje de comandos de shell para admitir ladf 2>&1 | grep 'foo'
sintaxis para ese propósito, pero también lobash
hace|&
.Lo que es importante tener en cuenta es que las tuberías siempre tratan con descriptores de archivo. Existe
FIFO
o tubería con nombre , que tiene un nombre de archivo en el disco y te permite utilizarlo como un archivo, pero se comporta como un tubo. Pero los|
tipos de tuberías son lo que se conoce como tubería anónima: no tienen nombre de archivo, porque en realidad son solo dos objetos conectados entre sí. El hecho de que no estamos tratando con archivos también tiene una implicación importante: las tuberías no sonlseek()
capaces. Los archivos, ya sea en la memoria o en el disco, son estáticos: los programas pueden usarlseek()
syscall para saltar al byte 120, luego regresar al byte 10 y luego avanzar hasta el final. Las tuberías no son estáticas: son secuenciales y, por lo tanto, no puede rebobinar los datos que obtiene de ellas conlseek()
. Esto es lo que hace que algunos programas se den cuenta si están leyendo desde un archivo o desde una tubería y, por lo tanto, pueden hacer los ajustes necesarios para un rendimiento eficiente; en otras palabras, aprog
puede detectar si lo hagocat file.txt | prog
o noprog < input.txt
. Ejemplo de trabajo real de eso es la cola .Las otras dos propiedades muy interesantes de las tuberías es que tienen un búfer, que en Linux tiene 4096 bytes , ¡y en realidad tienen un sistema de archivos como se define en el código fuente de Linux ! No son simplemente un objeto para pasar datos, ¡son una estructura de datos ellos mismos! De hecho, debido a que existe un sistema de archivos pipefs, que gestiona tuberías y FIFO, las tuberías tienen un número de inodo en su sistema de archivos respectivo:
En Linux, las canalizaciones son unidireccionales, al igual que la redirección. En algunas implementaciones tipo Unix, hay tuberías bidireccionales. Aunque con la magia de las secuencias de comandos de shell, también puede crear tuberías bidireccionales en Linux .
Ver también:
pipe()
syscall ydup2()
.<<
,<<<
se implementan como archivos temporales anónimos (no vinculados) enbash
yksh
, mientras se< <()
utilizan canalizaciones anónimas;/bin/dash
utiliza tuberías para<<
. Consulte ¿Cuál es la diferencia entre <<, <<< y <<en bash?fuente
Para agregar a las otras respuestas, también hay diferencias semánticas sutiles, por ejemplo, las tuberías se cierran más fácilmente que las redirecciones:
En el primer ejemplo, cuando
head
finaliza la primera llamada , cierra la tubería yseq
finaliza, por lo que no hay entrada disponible para la segundahead
.En el segundo ejemplo, head consume la primera línea, pero cuando cierra su propia
stdin
tubería , el archivo permanece abierto para la próxima llamada.El tercer ejemplo muestra que si usamos
read
para evitar cerrar la tubería, todavía está disponible dentro del subproceso.Entonces, el "flujo" es lo que atravesamos los datos (stdin, etc.), y es el mismo en ambos casos, pero la tubería conecta los flujos de dos procesos, donde una redirección conecta los flujos entre un proceso y un archivo, por lo que Puede ver la fuente de las similitudes y diferencias.
PD: Si tiene tanta curiosidad y / o sorpresa por esos ejemplos como yo, puede profundizar más
trap
para ver cómo se resuelven los procesos, por ejemplo:A veces, el primer proceso se cierra antes de
1
imprimirse, a veces después.También me pareció interesante usar
exec <&-
para cerrar la secuencia de la redirección para aproximar el comportamiento de la tubería (aunque con un error):fuente
read
consume solo la primera línea (eso es un byte para una1
nueva línea).seq
enviado en total 10 bytes (5 números y 5 líneas nuevas). Entonces quedan 8 bytes en el buffer de tubería, y es por eso que el segundohead
funciona: todavía hay datos disponibles en el buffer de tubería. Por cierto, la cabeza sale sólo si hay 0 bytes leídos, un poco como enhead /dev/null
seq 5 | (head -n1; head -n1)
la primera llamada se vacía la tubería, por lo que todavía existe en un estado abierto pero sin datos para la segunda llamadahead
? Entonces, ¿la diferencia de comportamiento entre la tubería y la redirección se debe a que la cabeza extrae todos los datos de la tubería, pero solo las 2 líneas del controlador de archivo?strace
comando que di en el primer comentario. Con la redirección, el archivo tmp está en el disco, lo que lo hace buscable (porque usanlseek()
syscall; los comandos pueden saltar el archivo desde el primer byte hasta el último como quieran). el trabajo es leer todo primero, o si el archivo es grande, asignar parte de él a la RAM a través de unammap()
llamada. Una vez hice el míotail
en Python, y me encontré exactamente con el mismo problema.(...)
, y la subshell hará una copia de su propio stdin en cada comando dentro(...)
. Por lo tanto, técnicamente se leen desde el mismo objeto. Primerohead
piensa que está leyendo de su propio stdin. Segundohead
piensa que tiene su propio stdin. Pero en realidad su fd # 1 (stdin) es solo una copia de la misma fd, que se lee al final de la tubería. Además, he publicado una respuesta, por lo que tal vez ayude a aclarar las cosas.He encontrado un problema con esto en C hoy. Esencialmente, Pipe también tiene diferentes semánticas para redirigir, incluso cuando se envía a
stdin
. Realmente creo que dadas las diferencias, las tuberías deberían ir a otro lugar que no seastdin
así,stdin
y llamemosstdpipe
(para hacer un diferencial arbitrario) se puede manejar de diferentes maneras.Considera esto. Cuando se canaliza la salida de un programa a otro,
fstat
parece que devuelve cero como ast_size
pesar dels -lha /proc/{PID}/fd
mostrar que hay un archivo. Al redirigir un archivo, este no es el caso (al menos en debianwheezy
,stretch
yjessie
vanilla y ubuntu14.04
,16.04
vanilla.Si
cat /proc/{PID}/fd/0
tiene una redirección, podrá repetir la lectura tantas veces como desee. Si hace esto con una tubería, notará que la segunda vez que ejecuta la tarea consecutivamente, no obtiene el mismo resultado.fuente