In einigen Bourne-wie Muscheln, die read
kann builtin nicht die ganze Zeile aus der Datei eingelesen /proc
(der Befehl unten ausgeführt werden sollte zsh
, ersetzen Sie $=shell
mit $shell
anderen Shells):
$ 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
Standard erfordert, dass die Standardeingabe eine Textdatei sein muss. Verursacht diese Anforderung das abwechslungsreiche Verhalten?
Lesen Sie die POSIX-Definition der Textdatei , ich mache eine Überprüfung:
$ 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
Es gibt kein NUL
Zeichen im Inhalt von /proc/sys/fs/file-max
und find
es wird auch als reguläre Datei gemeldet (Ist dies ein Fehler in find
?).
Ich denke, die Muschel hat etwas unter der Haube gemacht, wie file
:
$ file /proc/sys/fs/file-max
/proc/sys/fs/file-max: empty
strace
Erklärung auf der Grundlage von ist viel einfacher zu verstehen!cat /proc/sys/fs/file-max | ...
, ist das Problem weg.procfs
mehrere aufeinanderfolgenderead(2)
Aufrufe derselben Datei nicht verarbeitet werden können. Das Verhalten hängt nicht von der Shell ab. Das Verwendencat
und Weiterleiten funktioniert, dacat
die Datei in ausreichend großen Blöcken gelesen wird. Dieread
eingebaute Shell liest dann Zeichen für Zeichen aus der Pipe.mksh
.read -N 10 a < /proc/sys/fs/file-max
zsh
:read -u0 -k10
(oder verwendensysread
;$mapfile[/proc/sys/fs/file-max]
funktioniert nicht, da diese Dateien nicht bearbeitet werden könnenmmap
). In jedem Fall kann man bei jeder Schale immer dazua=$(cat /proc/sys/fs/file-max)
. Mit einigen einschließlichmksh
,zsh
undksh93
,a=$(</proc/sys/fs/file-max)
funktioniert auch und Gabel keinen Prozess das Lesen zu tun.Wenn Sie wissen möchten, warum? Dies ist so, Sie können die Antwort in den Kernel-Quellen hier sehen :
Grundsätzlich ist das Suchen (
*ppos
nicht 0) für reads (!write
) von sysctl-Werten, die Zahlen sind, nicht implementiert . Jedes Mal , wenn ein Lesen von getan wird/proc/sys/fs/file-max
, wird die Routine in Frage__do_proc_doulongvec_minmax()
wird aus dem Eintrag aufgerufen fürfile-max
in der Konfigurationstabelle in der gleichen Datei.Andere Einträge, wie sie beispielsweise
/proc/sys/kernel/poweroff_cmd
implementiert werdenproc_dostring()
, ermöglichen Suchvorgänge, sodass Siedd bs=1
problemlos darauf zugreifen und aus Ihrer Shell lesen können.Beachten Sie, dass seit Kernel 2.6 die meisten
/proc
Lesevorgänge über eine neue API namens seq_file implementiert wurden und dies Suchvorgänge unterstützt, sodass z. B. das Lesen/proc/stat
keine Probleme verursachen sollte./proc/sys/
Wie wir sehen können, verwendet die Implementierung diese API nicht.quelle
Beim ersten Versuch sieht dies wie ein Fehler in den Shells aus, der weniger als eine echte Bourne-Shell zurückgibt, oder seine Derivate (sh, bosh, ksh, heirloom).
Die ursprüngliche Bourne-Shell versucht, einen Block (64 Byte) zu lesen. Neuere Bourne-Shell-Varianten lesen 128 Byte, aber sie beginnen erneut mit dem Lesen, wenn kein neues Zeilenzeichen vorhanden ist.
Hintergrund: / procfs und ähnliche Implementierungen (zB die montierte
/etc/mtab
virtuelle Datei) haben dynamische Inhalte und einstat()
Anruf nicht Ursache der Neuschöpfung des dynamischen Inhalts zuerst. Aus diesem Grund kann die Größe einer solchen Datei (vom Lesen bis zur EOF) von der zurückgegebenen Datei abweichenstat()
.Da der POSIX-Standard voraussetzt, dass Dienstprogramme jederzeit mit kurzen Lesevorgängen rechnen müssen , ist eine Software, die glaubt, dass ein Wert, der
read()
weniger als die bestellte Anzahl von Bytes zurückgibt, ein EOF-Hinweis ist, fehlerhaft. Ein korrekt implementiertes Dienstprogramm ruftread()
ein zweites Mal auf, wenn es weniger als erwartet zurückgibt - bis eine 0 zurückgegeben wird. Im Falle desread
eingebauten ist es natürlich ausreichend zu lesen, bisEOF
oder bis ein angezeigtNL
wird.Wenn Sie
truss
einen Truss-Klon ausführen , sollten Sie in der Lage sein, das falsche Verhalten für die Shells zu überprüfen, die nur6
in Ihrem Experiment zurückkehren.In diesem speziellen Fall scheint es sich um einen Linux-Kernel-Fehler zu handeln, siehe:
Der Linux-Kernel gibt mit der Sekunde 0 zurück
read
und dies ist natürlich falsch.Fazit: Shells, die zuerst versuchen, einen ausreichend großen Datenblock zu lesen, lösen diesen Linux-Kernel-Fehler nicht aus.
quelle
Die Dateien unter / proc verwenden manchmal NULL-Zeichen, um Felder in der Datei zu trennen. Es scheint, dass read damit nicht umgehen kann.
quelle