En algunos Bourne como conchas, la read
orden interna no puede leer toda la línea del archivo en /proc
(el siguiente comando debe ser ejecutado en zsh
, sustituir $=shell
con $shell
otras conchas):
$ for shell in bash dash ksh mksh yash zsh schily-sh heirloom-sh "busybox sh"; do
printf '[%s]\n' "$shell"
$=shell -c 'IFS= read x </proc/sys/fs/file-max; echo "$x"'
done
[bash]
602160
[dash]
6
[ksh]
602160
[mksh]
6
[yash]
6
[zsh]
6
[schily-sh]
602160
[heirloom-sh]
602160
[busybox sh]
6
read
El estándar requiere que la entrada estándar deba ser un archivo de texto , ¿ese requisito causa comportamientos variados?
Lea la definición POSIX del archivo de texto , hago algunas verificaciones:
$ od -t a </proc/sys/fs/file-max
0000000 6 0 2 1 6 0 nl
0000007
$ find /proc/sys/fs -type f -name 'file-max'
/proc/sys/fs/file-max
No hay NUL
carácter en el contenido de /proc/sys/fs/file-max
, y también lo find
informó como un archivo normal (¿Es esto un error find
?).
Supongo que el caparazón hizo algo debajo del capó, como file
:
$ file /proc/sys/fs/file-max
/proc/sys/fs/file-max: empty
strace
explicación basada en datos es mucho más fácil de entender!cat /proc/sys/fs/file-max | ...
, el problema se ha ido.procfs
no puede manejar múltiplesread(2)
llamadas sucesivas al mismo archivo; El comportamiento no depende del shell. El usocat
y la tubería funciona porquecat
lee el archivo en fragmentos lo suficientemente grandes; el shellread
incorporado luego lee de la tubería un carácter a la vez.mksh
.read -N 10 a < /proc/sys/fs/file-max
zsh
:read -u0 -k10
(o usosysread
;$mapfile[/proc/sys/fs/file-max]
no funciona ya que esos archivos no se puedenmmap
editar). En cualquier caso, con cualquier shell, siempre se puedea=$(cat /proc/sys/fs/file-max)
. Algunos incluyenmksh
,zsh
yksh93
,a=$(</proc/sys/fs/file-max)
también funciona y no bifurca un proceso para hacer la lectura.Si estás interesado en saber por qué? Esto es así, puede ver la respuesta en las fuentes del núcleo aquí :
Básicamente, la búsqueda (
*ppos
no 0) no se implementa para lecturas (!write
) de valores sysctl que son números. Cada vez que se realiza una lectura/proc/sys/fs/file-max
, la rutina en cuestión__do_proc_doulongvec_minmax()
se llama desde la entrada defile-max
la tabla de configuración en el mismo archivo.Otras entradas, como las que
/proc/sys/kernel/poweroff_cmd
se implementan a través de lasproc_dostring()
cuales permiten búsquedas, para que pueda hacerlodd bs=1
y leer desde su shell sin problemas.Tenga en cuenta que desde el kernel 2.6 la mayoría de las
/proc
lecturas se implementaron a través de una nueva API llamada seq_file y esto admite búsquedas, por ejemplo, la lectura/proc/stat
no debería causar problemas. La/proc/sys/
implementación, como podemos ver, no utiliza esta API.fuente
En el primer intento, esto parece un error en los shells que devuelven menos que un Bourne Shell real o sus derivados (sh, bosh, ksh, reliquia).
El Bourne Shell original intenta leer un bloque (64 bytes). Las variantes más recientes del Bourne Shell leen 128 bytes, pero comienzan a leer nuevamente si no hay un nuevo carácter de línea.
Antecedentes: / procfs e implementaciones similares (por ejemplo, el
/etc/mtab
archivo virtual montado ) tienen contenido dinámico y unastat()
llamada no causa 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 questat()
devuelve.Dado que el estándar POSIX requiere que las empresas de servicios públicos esperen lecturas cortas en cualquier momento, el software que cree que un valor
read()
que devuelve menos que la cantidad ordenada de bytes es una indicación EOF está roto. Una utilidad implementada correctamente llamaread()
por segunda vez en caso de que devuelva menos de lo esperado, hasta que se devuelva un 0. En el caso de laread
construcción, por supuesto, sería suficiente leer hastaEOF
o hasta queNL
se vea un.Si corres
truss
o haces un clon de truss, deberías poder verificar ese comportamiento incorrecto para los shells que solo regresan6
en tu experimento.En este caso especial, parece ser un error del kernel de Linux, vea:
El kernel de Linux devuelve 0 con el segundo
read
y, por supuesto, esto es incorrecto.Conclusión: los shells que primero intentan leer una porción de datos lo suficientemente grande no activan este error del kernel de Linux.
fuente
Los archivos bajo / proc a veces usan caracteres NULL para separar los campos dentro del archivo. Parece que leer no puede manejar esto.
fuente