Em alguns Bourne-como conchas, o read
embutida não pode ler toda a linha a partir do arquivo em /proc
(o comando a seguir devem ser executados em zsh
, substitua $=shell
com $shell
com outras 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
padrão exige que a entrada padrão precise ser um arquivo de texto ; esse requisito causa comportamentos variados?
Leia a definição POSIX do arquivo de texto , faço algumas verificações:
$ 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
Não há NUL
caractere no conteúdo de /proc/sys/fs/file-max
, e também o find
relatou como um arquivo regular (isso é um bug find
?).
Eu acho que a concha fez algo sob o capô, como file
:
$ file /proc/sys/fs/file-max
/proc/sys/fs/file-max: empty
strace
explicação baseada em é muito mais fácil de entender!cat /proc/sys/fs/file-max | ...
, o problema se foi.procfs
não é possível lidar com váriasread(2)
chamadas sucessivas para o mesmo arquivo; o comportamento não depende do shell. Usarcat
e canalizar funciona porquecat
lê o arquivo em pedaços grandes o suficiente; oread
built-in do shell então lê do pipe um caractere de cada vez.mksh
.read -N 10 a < /proc/sys/fs/file-max
zsh
:read -u0 -k10
(ou usesysread
;$mapfile[/proc/sys/fs/file-max]
não funciona porque esses arquivos não podem sermmap
editados). Em qualquer caso, com qualquer shell, sempre é possívela=$(cat /proc/sys/fs/file-max)
. Com alguns incluindomksh
,zsh
eksh93
,a=$(</proc/sys/fs/file-max)
também funciona e não bifurca um processo para fazer a leitura.Se você está interessado em saber o porquê? assim é, você pode ver a resposta nas fontes do kernel aqui :
Basicamente, a busca (
*ppos
não 0) não é implementada para leituras (!write
) de valores sysctl que são números. Sempre que uma leitura é feita/proc/sys/fs/file-max
, a rotina em questão__do_proc_doulongvec_minmax()
é chamada a partir da entrada parafile-max
na tabela de configuração no mesmo arquivo.Outras entradas, como as que
/proc/sys/kernel/poweroff_cmd
são implementadasproc_dostring()
, permitem a busca, para que você possa fazerdd bs=1
isso e ler a partir do seu shell sem problemas.Observe que, desde o kernel 2.6, a maioria das
/proc
leituras foi implementada por meio de uma nova API chamada seq_file e isso suporta buscas, por exemplo, a leitura/proc/stat
não deve causar problemas. A/proc/sys/
implementação, como podemos ver, não usa essa API.fonte
Na primeira tentativa, isso parece um bug nas conchas que retornam menos que um Bourne Shell real ou seus derivados derivam (sh, bosh, ksh, herança).
O Bourne Shell original tenta ler um bloco (64 bytes) mais recentes, as variantes do Bourne Shell leem 128 bytes, mas começam a ler novamente se não houver um novo caractere de linha.
Antecedentes: / procfs e implementações similares (por exemplo, o
/etc/mtab
arquivo virtual montado ) possuem conteúdo dinâmico e umastat()
chamada não causa a recriação do conteúdo dinâmico primeiro. Por esse motivo, o tamanho de um arquivo (da leitura até o EOF) pode diferir do questat()
retorna.Dado que o padrão POSIX exige que os utilitários esperem leituras curtas a qualquer momento, o software que acredita que um
read()
que retorna menos que a quantidade solicitada de bytes é uma indicação EOF está quebrado. Um utilitário implementado corretamente chamaread()
uma segunda vez, caso retorne menos que o esperado - até que um 0 seja retornado. No caso doread
builtin, é claro que seria suficiente ler atéEOF
ou até que umNL
seja visto.Se você executar
truss
ou um clone de treliça, poderá verificar esse comportamento incorreto para as conchas que retornam apenas6
em seu experimento.Nesse caso especial, parece ser um bug do kernel do Linux, veja:
O kernel do Linux retorna 0 com o segundo
read
e isso está incorreto.Conclusão: os shells que primeiro tentam ler uma grande quantidade de dados não acionam esse bug do kernel do Linux.
fonte
Os arquivos em / proc às vezes usam caracteres NULL para separar os campos dentro do arquivo. Parece que a leitura não é capaz de lidar com isso.
fonte