La canalización es un archivo abierto en un sistema de archivos en el núcleo y no es accesible como un archivo normal en el disco. Se almacena automáticamente solo en un cierto tamaño y eventualmente se bloqueará cuando esté lleno. A diferencia de los archivos originados en dispositivos de bloque, las canalizaciones se comportan de manera muy similar a los dispositivos de caracteres, por lo que generalmente no son compatibles lseek()
y los datos que se leen de ellos no se pueden volver a leer como lo haría con un archivo normal.
La cadena aquí es un archivo normal creado en un sistema de archivos montado. El shell crea el archivo y retiene su descriptor mientras elimina inmediatamente su único enlace al sistema de archivos (y así lo elimina) antes de escribir / leer un byte en / desde el archivo. El kernel mantendrá el espacio requerido para el archivo hasta que todos los procesos liberen todos los descriptores. Si el niño que lee de tal descriptor tiene la capacidad de hacerlo, puede rebobinarlo lseek()
y leerlo nuevamente.
En ambos casos, los tokens <<<
y |
los descriptores de archivo representan no necesariamente los archivos en sí. Puede obtener una mejor idea de lo que está sucediendo haciendo cosas como:
readlink /dev/fd/1 | cat
...o...
ls -l <<<'' /dev/fd/*
La diferencia más significativa entre los dos archivos es que here-string / doc es prácticamente un asunto de una sola vez: el shell escribe todos los datos en él antes de ofrecer el descriptor de lectura al niño. Por otro lado, el shell abre la tubería en los descriptores apropiados y bifurca a los niños para administrarlos para la tubería, por lo que se escribe / lee simultáneamente en ambos extremos.
Sin embargo, estas distinciones solo son generalmente ciertas. Hasta donde yo sé (que en realidad no es tan lejos), esto es cierto para casi todos los shell que manejan la <<<
abreviatura here-string para <<
una redirección here-document con la única excepción de yash
. yash
, busybox
, dash
, Y otras ash
variantes tienden a respaldar los documentos internos de tuberías, sin embargo, y por lo que en esas conchas realmente hay muy poca diferencia entre los dos, después de todo.
Ok, dos excepciones. Ahora que lo estoy pensando, en ksh93
realidad no sirve para nada |
, sino que maneja todo el negocio con sockets, aunque sí hace un archivo tmp eliminado para la <<<*
mayoría de los demás. Además, solo coloca las secciones separadas de una tubería en un entorno de subshell que es una especie de eufemismo POSIX porque al menos actúa como un subshell y, por lo tanto, ni siquiera hace las horquillas.
El hecho es que los resultados de referencia de @ PSkocik (que es muy útil) aquí pueden variar ampliamente por muchas razones, y la mayoría de estos dependen de la implementación. Para la configuración del documento aquí, los factores más importantes serán el ${TMPDIR}
tipo de sistema de archivos objetivo y la configuración / disponibilidad de caché actual, y aún más la cantidad de datos que se escribirán. Para la tubería, será del tamaño del proceso de shell en sí, porque se hacen copias para las horquillas requeridas. De esta manera, bash
es terrible en la configuración de la canalización (para incluir sustituciones de $(
comandos )
) , porque es grande y muy lento, pero ksh93
casi no hace ninguna diferencia.
Aquí hay otro pequeño fragmento de shell para demostrar cómo un shell se divide de los subshell para una tubería:
pipe_who(){ echo "$$"; sh -c 'echo "$PPID"'; }
pipe_who
pipe_who | { pipe_who | cat /dev/fd/3 -; } 3<&0
32059 #bash's pid
32059 #sh's ppid
32059 #1st subshell's $$
32111 #1st subshell sh's ppid
32059 #2cd subshell's $$
32114 #2cd subshell sh's ppid
La diferencia entre lo que pipe_who()
informa una llamada canalizada y el informe de una ejecución en el shell actual se debe al comportamiento especificado de un (
subshell )
de reclamar el pid del shell padre $$
cuando se expande. Aunque los bash
subsales definitivamente son procesos separados, el $$
parámetro especial del shell no es una fuente confiable de esta información. Aún así, el sh
shell secundario del subshell no se niega a informar con precisión su $PPID
.
No hay sustituto para la evaluación comparativa:
Y para una mayor cantidad de datos:
Parece que la versión de tubería tiene un costo de configuración mayor pero al final es más eficiente.
fuente
echo foo >/dev/shm/1;cat /dev/shm/1 >/dev/null
parecía ser rápido en ambos casos ...echo "$longstring"
o<<<"$longstring"
sería ajustado para la eficiencia y con cadenas cortas, la eficiencia no importa mucho de todos modos.cat <(echo foo) >/dev/null
sea más rápido queecho foo | cat >/dev/null
.