Проблема в том, что эти /proc
файлы в Linux выглядят как текстовые файлы, что касается stat()/fstat()
, но не ведут себя как таковые.
Поскольку это динамические данные, вы можете выполнить только один системный вызов read()
для них (по крайней мере, для некоторых из них). Если сделать больше одного, то можно получить два куска с разным содержимым, так что вместо этого, похоже, второй read()
на них просто ничего не вернет (что означает конец файла) (если только вы не lseek()
вернетесь к началу (и только к началу)).
Утилита read
должна читать содержимое файлов по одному байту за раз, чтобы быть уверенной, что не прочтет больше символа новой строки. Вот что делает dash
:
$ strace -fe read dash -c 'read a < /proc/sys/fs/file-max'
read(0, "1", 1) = 1
read(0, "", 1) = 0
Некоторые оболочки, такие как bash
, имеют оптимизацию, чтобы избежать необходимости выполнять много системных вызовов read()
. Сначала они проверяют, является ли файл искомым, и если да, то читают кусками, так как тогда они знают, что могут вернуть курсор обратно сразу после новой строки, если они прочитали мимо нее:
$ 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
С bash
у вас все еще будут проблемы для файлов proc размером более 128 байт, которые можно прочитать только за один системный вызов read.
bash
также, похоже, отключает эту оптимизацию при использовании опции -d
.
ksh93
заводит оптимизацию еще дальше, настолько, что она становится фальшивой. read
ksh93 выполняет поиск назад, но запоминает дополнительные данные, которые он прочитал, для следующего read
, поэтому следующий read
(или любой другой его встроенный модуль, читающий данные, например cat
или head
) даже не пытается read
данные (даже если эти данные были изменены другими командами в промежутке):
$ 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