В некоторых Bourne-подобные оболочкам, то read
встроенный не может прочитать всю строку из файла /proc
(команда ниже должны быть запущены в zsh
, замените $=shell
с $shell
другими оболочками):
$ 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
Стандарт требует, чтобы стандартным вводом был текстовый файл , вызывает ли это требование различное поведение?
Прочитайте определение текстового файла POSIX , я делаю некоторые проверки:
$ 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
Там нет NUL
символа в содержании /proc/sys/fs/file-max
, а также find
сообщил об этом как обычный файл (это ошибка в find
?).
Я думаю, что оболочка сделала что-то под капотом, как file
:
$ file /proc/sys/fs/file-max
/proc/sys/fs/file-max: empty
strace
объяснение на основе гораздо легче понять!cat /proc/sys/fs/file-max | ...
, проблема исчезла.procfs
они не могут обрабатывать несколько последовательныхread(2)
вызовов одного и того же файла; поведение не зависит от оболочки. Использованиеcat
и конвейерная обработка работают, потому чтоcat
читает файл достаточно большими кусками;read
встроенная оболочка затем читает из канала по одному символу за раз.mksh
.read -N 10 a < /proc/sys/fs/file-max
zsh
:read -u0 -k10
(или использоватьsysread
;$mapfile[/proc/sys/fs/file-max]
не работает, так как эти файлы не могут бытьmmap
отредактированы). В любом случае с любой оболочкой всегда можноa=$(cat /proc/sys/fs/file-max)
. С некоторыми, в том числеmksh
,zsh
иksh93
,a=$(</proc/sys/fs/file-max)
также работает и не разворачивает процесс для чтения.Если вам интересно узнать почему? это так, вы можете увидеть ответ в исходниках ядра здесь :
По сути, поиск (
*ppos
не 0) не реализован для reads (!write
) значений sysctl, которые являются числами. Всякий раз, когда выполняется чтение/proc/sys/fs/file-max
, соответствующая подпрограмма__do_proc_doulongvec_minmax()
вызывается из записиfile-max
в таблице конфигурации в том же файле.Другие записи, такие как
/proc/sys/kernel/poweroff_cmd
реализованные черезproc_dostring()
которые разрешают поиск, так что вы можете делатьdd bs=1
это и читать из вашей оболочки без проблем.Обратите внимание, что, начиная с ядра 2.6, большинство операций
/proc
чтения было реализовано с помощью нового API под названием seq_file, и это поддерживает поиск, поэтому, например, чтение/proc/stat
не должно вызывать проблем./proc/sys/
Реализация, как мы можем видеть, не использовать этот API.источник
С первой попытки это выглядит как ошибка в оболочках, которые возвращают меньше, чем реальная оболочка Борна или ее производные (sh, bosh, ksh, семейная реликвия).
Оригинальная оболочка Bourne Shell пытается прочитать блок (64 байта), более новые варианты оболочки Bourne Shell читают 128 байтов, но они начинают читать снова, если нет символа новой строки.
Предпосылки: / procfs и подобные реализации (например, смонтированный
/etc/mtab
виртуальный файл) имеют динамическое содержимое, иstat()
вызов не вызывает повторного создания динамического содержимого в первую очередь. По этой причине размер такого файла (от чтения до EOF) может отличаться от того, чтоstat()
возвращается.Учитывая, что стандарт POSIX требует, чтобы утилиты ожидали коротких чтений в любое время, программное обеспечение, которое считает, что a,
read()
который возвращает меньше, чем упорядоченный объем байтов, является признаком EOF, не работает. Правильно реализованная утилита вызываетread()
второй раз, если возвращает меньше ожидаемого - до тех пор, пока не будет возвращено 0. В случаеread
встроенного, конечно, было бы достаточно, чтобы прочитать доEOF
или пока неNL
будет видно.Если вы запускаете
truss
или клон фермы, вы должны быть в состоянии проверить это неправильное поведение для оболочек, которые возвращаются только6
в вашем эксперименте.В этом особом случае это ошибка ядра Linux, см .:
Ядро Linux возвращает 0 со вторым,
read
и это, конечно, неправильно.Вывод: Оболочки, которые сначала пытаются прочитать достаточно большой кусок данных, не вызывают эту ошибку ядра Linux.
источник
Файлы в / proc иногда используют символ NULL для разделения полей внутри файла. Кажется, что чтение не может справиться с этим.
источник