一部のシェル組み込み機能が「/proc」のファイルの全行を「読み取れない」のはなぜですか?

一部のシェル組み込み機能が「/proc」のファイルの全行を「読み取れない」のはなぜですか?

一部の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

ベストアンサー1

問題は、/procLinuxでは、これらのファイルはstat()/fstat()テキストファイルのように見えますが、それはうまくいかないということです。

動的データであるため、read()そのデータに対して1つのシステムコールしか実行できません(少なくとも一部のデータについては)。複数の操作を実行すると、内容が異なる2つのチャンクが発生する可能性があるため、2番目の操作は何も返さないようですread()(ファイルの終わりを意味します)(lseek()最初に戻らない限り(そして先頭のみ))。

ユーティリティreadは一度に1バイトずつファイルの内容を読み、改行文字のみが読み取られるようにする必要があります。これは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

を使用すると、bash128バイトを超え、単一の読み取りシステム呼び出しでのみ読み取ることができるprocファイルで問題が発生します。

bash-dこのオプションを使用すると、この最適化も無効になっているように見えます。

ksh93追加の最適化はさらに偽になります。 ksh93はread逆追跡を実行しますが、nextのために読み取った追加のデータを記憶するので、readnext(またはreadなどのデータを読み取る他の組み込み関数)は、異なるコマンド間でそのデータを試行しません(修正された場合でも)。 :catheadread

$ 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

おすすめ記事