GNU/Linux >> Tutoriales Linux >  >> Linux

¿Por qué algunos shells `read` incorporados no pueden leer la línea completa del archivo en `/proc`?

El problema es que esos /proc los archivos en Linux aparecen como archivos de texto hasta stat()/fstat() se preocupa, pero no se comporte como tal.

Debido a que son datos dinámicos, solo puedes hacer una read() llamada del sistema sobre ellos (al menos para algunos de ellos). Hacer más de uno podría obtener dos fragmentos de dos contenidos diferentes, por lo que parece un segundo read() en ellos simplemente no devuelve nada (es decir, final de archivo) (a menos que lseek() volver al principio (y sólo al principio)).

El read La utilidad necesita leer el contenido de los archivos un byte a la vez para asegurarse de no leer más allá del carácter de nueva línea. Eso es lo que dash hace:

 $ strace -fe read dash -c 'read a < /proc/sys/fs/file-max'
 read(0, "1", 1)                         = 1
 read(0, "", 1)                          = 0

Algunas conchas como bash tener una optimización para no tener que hacer tantos read() llamadas del sistema. Primero verifican si el archivo se puede buscar y, de ser así, lo leen en fragmentos, ya que saben que pueden volver a colocar el cursor justo después de la nueva línea si han leído más allá:

$ strace -e lseek,read bash -c 'read a' < /proc/sys/fs/file-max
lseek(0, 0, SEEK_CUR)                   = 0
read(0, "1628689\n", 128)               = 8

Con bash , aún tendría problemas con los archivos proc que tienen más de 128 bytes y solo se pueden leer en una llamada al sistema de lectura.

bash también parece deshabilitar esa optimización cuando -d se utiliza la opción.

ksh93 lleva la optimización aún más lejos hasta el punto de volverse falsa. read de ksh93 busca hacia atrás, pero recuerda los datos adicionales que ha leído para el siguiente read , por lo que el próximo read (o cualquiera de sus otras funciones integradas que leen datos como cat o head ) ni siquiera intenta read los datos (incluso si esos datos han sido modificados por otros comandos intermedios):

$ seq 10 > a; ksh -c 'read a; echo test > a; read b; echo "$a $b"' < a
1 2
$ seq 10 > a; sh -c 'read a; echo test > a; read b; echo "$a $b"' < a
1 st

Si te interesa saber ¿por qué? esto es así, puedes ver la respuesta en las fuentes del núcleo aquí:

    if (!data || !table->maxlen || !*lenp || (*ppos && !write)) {
            *lenp = 0;
            return 0;
    }

Básicamente, buscando (*ppos not 0) no está implementado para lecturas (!write )de valores sysctl que son números. Cada vez que se realiza una lectura desde /proc/sys/fs/file-max ,la rutina en cuestión__do_proc_doulongvec_minmax() se llama desde la entrada para file-max en la tabla de configuración en el mismo archivo.

Otras entradas, como /proc/sys/kernel/poweroff_cmd se implementan a través de proc_dostring() que permite búsquedas, por lo que puede hacer dd bs=1 en él y lea desde su shell sin problemas.

Tenga en cuenta que desde el kernel 2.6 la mayoría /proc las lecturas se implementaron a través de una nueva API llamada seq_file y esto admite búsquedas, por ejemplo, leer /proc/stat no debe causar problemas. El /proc/sys/ La implementación, como podemos ver, no usa thisapi.


En el primer intento, esto parece un error en los proyectiles que devuelven menos que un Bourne Shell real o sus derivados (sh, bosh, ksh, heirloom).

El Bourne Shell original intenta leer un bloque (64 bytes); las variantes más nuevas de Bourne Shell leen 128 bytes, pero comienzan a leer de nuevo si no hay un carácter de nueva línea.

Antecedentes:/procfs e implementaciones similares (por ejemplo, el /etc/mtab montado archivo virtual) tienen contenido dinámico y un stat() la llamada no provoca la recreación del contenido dinámico primero. Por esta razón, el tamaño de dicho archivo (desde la lectura hasta el EOF) puede diferir de lo que stat() regresa.

Dado que el estándar POSIX requiere que las utilidades esperen lecturas cortas en cualquier momento, el software que crea que un read() que devuelve menos de lo pedido cantidad de bytes es una indicación EOF están rotos. Una utilidad implementada correctamente llama a read() una segunda vez en caso de que devuelva menos de lo esperado, hasta que se devuelva un 0. En el caso del read incorporado, por supuesto sería suficiente leer hasta EOF o hasta un NL se ve.

Si ejecuta truss o un clon de truss, debería poder verificar ese comportamiento incorrecto para los shells que solo devuelven 6 en su experimento.

En este caso especial, parece ser un error del kernel de Linux, consulte:

$ sdd -debug bs=1 if= /proc/sys/fs/file-max 
Simple copy ...
readbuf  (3, 12AC000, 1) = 1
writebuf (1, 12AC000, 1)
8readbuf  (3, 12AC000, 1) = 0

sdd: Read  1 records + 0 bytes (total of 1 bytes = 0.00k).
sdd: Wrote 1 records + 0 bytes (total of 1 bytes = 0.00k).

El kernel de Linux devuelve 0 con el segundo read y esto es, por supuesto, incorrecto.

Conclusión:los shells que primero intentan leer una porción de datos lo suficientemente grande no desencadenan este error del kernel de Linux.


Linux
  1. ¿Por qué el descriptor de archivo se abre y se lee solo una vez?

  2. ¿Cómo leer la penúltima línea en un archivo usando Bash?

  3. ¿Cómo borrar el contenido de un archivo desde la línea de comando?

  4. ¿Cuál es la forma más rápida de agregar texto a un archivo desde la línea de comandos?

  5. ¿Por qué rsync no puede copiar archivos de /sys en Linux?

Cómo leer archivos línea por línea en Bash

Cómo leer un archivo línea por línea en Bash

¿Por qué bifurcar mi proceso hace que el archivo se lea infinitamente?

¿Por qué falla el apagado de net rpc con las credenciales correctas?

¿Cómo obtener la URL del archivo de Dropbox desde la línea de comando?

Linux:grep desde ciertas líneas hasta el final del archivo