Cuando se utilizan tuberías, por ejemplo.
sudo cat /dev/sda | strings | less
Puedo moverme por las líneas de cadenas de mi dispositivo sda. Pero, ¿el contenido del dispositivo sda está completamente cargado y enviado al flujo de salida de cat? ¿O se evalúan las nuevas líneas cada vez que un programa solicita resultados de cat? (es decir, presiono j en el buscapersonas menos)
Respuesta1
Esto tiene más que ver con cómo less
funciona que con cómo cat
funciona strings
.
El cat
comando solo enviará datos a su salida estándar y se bloqueará siempre que el búfer de canalización entre él y strings
esté lleno y nadie esté leyendo. cat
realiza un almacenamiento en búfer mínimo por sí solo y el búfer de tubería suele ser pequeño.
Esto también es válido para strings
. Procesará los datos cat
y se bloqueará cuando less
no esté leyendo los datos que strings
produce.
less
almacenará en búfer su entrada para permitirle moverse hacia adelante y hacia atrás en los datos que muestra. Cuando se desplace a la página siguiente, less
leerá más datos strings
en su búfer. Mientras no se esté desplazando hacia adelante, creo que less
solo leerá una cantidad limitada de datos (y, por lo tanto, strings
se cat
bloqueará mientras no se esté desplazando hacia adelante).
Si canaliza una gran cantidad de datos a less
, se utilizará bastante memoria para este almacenamiento en búfer.sidecides leerlo todo hasta el final con less
.
Hay una opción, -B
que limita la cantidad de memoria utilizada para el almacenamiento en búfer a 64 kilobytes (o la cantidad que especifique con la -b
opción). Limitar el tamaño del búfer de esta manera evitará que retroceda más de lo que se puede almacenar en el espacio del búfer especificado, pero también le permitirá leer grandes cantidades de datos sin less
quedarse sin memoria.
Consulte también man less
en su sistema.
Respuesta2
Las canalizaciones tienen un espacio de búfer limitado y, si un lector de canalizaciones (como less
en su ejemplo) no lee más datos de la canalización, el escritor se bloqueará después de llenar el búfer. Esto afectará al strings
comando, que a su vez lo bloqueará cat
una vez que su canal esté lleno.
Naturalmente, el cat
comando no puede leer todo el contenido del dispositivo sda en la memoria principal, por lo que si se cambian bloques que aún no han sido leídos, cat
verá el contenido modificado.
Respuesta3
Tanto cat
y strings
como la mayoría de utilidades similares¹, leen un poco de entrada a la vez, la procesan, luego leen más entradas, y así sucesivamente. Entonces, en su caso, cat
solo lee lo que less
se muestra, más un poco más de lo que está en tránsito.
Más detalladamente, el funcionamiento básico de cat
es:
- Reserve unos pocos kilobytes de memoria para utilizarlos como búfer.
- Si bien hay más entradas disponibles:
- Lea hasta N bytes de entrada en el búfer. (Esto sobrescribe los datos que se escribieron en un ciclo anterior).
- Escriba el contenido del búfer en la salida.
La operación de escritura se bloquea hasta que haya un lugar para copiar la salida. Cuando la salida de una tubería, la tubería en sí consume un poco de memoria en el núcleo, lo que se llamaamortiguador de tubería. Una vez que esté lleno, si cat
intenta escribir en la tubería, el intento de escritura se bloquea hasta que haya espacio. Puede haber espacio en el búfer de la tubería cuando el proceso en el extremo de lectura de la tubería lee algunos datos.
El strings
programa funciona de la misma manera que cat
, excepto que no copia toda la entrada, solo partes seleccionadas.
El less
programa funciona un poco diferente: guarda todo lo que lee en la memoria. No recicla su búfer, sigue haciéndolo crecer mientras siguen llegando más entradas. Sin embargo, la parte de lectura es similar en que less
solo lee datos cuando los necesita: solo lee hasta la última línea que muestra. , además de un poco más que lee con anticipación si está disponible.
Entonces, cuando ejecutas sudo cat /dev/sda | strings | less
, lo que se ha leído /dev/sda
consta de:
- Datos que
less
ya se han mostrado (o pasado). - Hasta unos pocos kB de datos
less
leídos pero aún no mostrados. - Hasta unos pocos kB en el búfer de tubería entre
strings
yless
. - Hasta unos pocos kB en la memoria de
strings
. - Hasta unos pocos kB en el búfer de tubería entre
cat
ystrings
. - Hasta unos pocos kB en la memoria de
cat
.
Puede observar cuándo cada programa lee y escribe datos rastreando sus llamadas al sistema:
sudo strace -e read,write -o cat.strace cat /dev/sda | strace -e read,write -o cat.strace strings | strace -e read,write -o less.strace less
y mira los *.strace
archivos. También puede verificar cuánto cat
se ha leído verificando el desplazamiento del archivo, por ejemplo con lsof -p1234
o con head /proc/1234/fdinfo/0
dónde 1234
está el ID del proceso cat
.
¹ Entre las utilidades básicas de procesamiento de texto, la principal excepción es sort
, que no puede emitir ningún resultado hasta que haya leído toda la entrada: por lo que sabe, la primera línea de salida bien puede ser la última línea de entrada a la que llega.
Respuesta4
En algunos sistemas (por ejemplo, MS-Dos), la canalización se implementa copiando la salida del primer comando en un archivo y luego ejecutando el segundo comando para leer desde este archivo. Unix no lo hace de esa manera.
En Unix es como una línea de producción. Cada etapa funciona simultáneamente, leyendo entradas y produciendo salidas. Si el proceso A produce más rápido de lo que consume el proceso B, entonces hay una acumulación de existencias entre el proceso A y B. Cuando esto es demasiado (½ KiB a 4 KiB), el proceso A se detiene. Cuando no hay stock para que B procese, B se pone en pausa. Los procesos se pausan y se reanudan para mantener bajos los niveles de existencias.
Al código de estos programas no le importa nada de esto. Simplemente lee la entrada y escribe la salida. Si intenta leer antes de que los datos estén disponibles, o intenta escribir antes de que el siguiente proceso esté listo, el sistema operativo lo pausará hasta que esté listo.
Cuando no hay más para leer (y no hay nada más en camino), el lector obtiene un final de archivo y sale. Esto, a su vez, provoca un fin de archivo en el siguiente proceso.