なしの同様のスクリプトですが、sudo
結果は同様です。
$ cat script.sh
#!/bin/bash
sed -e 's/^/--/'
whoami
$ bash < script.sh
--whoami
$ dash < script.sh
itvirta
を使用するbash
と、残りのスクリプトはへの入力として使用されsed
、を使用するdash
と、シェルがスクリプトを解釈します。
strace
それらで実行:dash
スクリプトのブロックを読み取り(ここでは8 kB、スクリプト全体を保持するのに十分な量)、次に生成しsed
ます。
read(0, "#!/bin/bash\nsed -e 's/^/--/'\nwho"..., 8192) = 36
stat("/bin/sed", {st_mode=S_IFREG|0755, st_size=73416, ...}) = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|...
つまり、ファイルハンドルはファイルの最後にあり、sed
入力は表示されません。内でバッファリングされている残りの部分dash
。(スクリプトが8 kBのブロックサイズよりも長い場合、残りの部分はによって読み取られsed
ます。)
一方、bashは最後のコマンドの終わりまでシークします。
read(0, "#!/bin/bash\nsed -e 's/^/--/'\nwho"..., 36) = 36
stat("/bin/sed", {st_mode=S_IFREG|0755, st_size=73416, ...}) = 0
...
lseek(0, -7, SEEK_CUR) = 29
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|...
次のように、入力がパイプからのものである場合:
$ cat script.sh | bash
パイプとソケットがシークできないため、巻き戻しを実行できません。この場合、Bashは一度に1文字ずつ入力を読み取るようにフォールバックし、読み過ぎを防ぎます。(fd_to_buffered_stream()
中にinput.c
各バイトのための完全なシステムコールを行う)は、原則的に非常に効果的ではありません。実際には、読み取りが大きなオーバーヘッドになるとは思いません。たとえば、シェルが行うほとんどのことはまったく新しいプロセスの生成を伴うという事実とは異なります。
同様の状況はこれです:
echo -e 'foo\nbar\ndoo' | bash -c 'read a; head -1'
サブシェルはread
、最初の改行のみを読み取るようにしhead
て、次の行が見えるようにする必要があります。(これも動作しdash
ます。)
言い換えると、Bashは、スクリプト自体とそれから実行されるコマンドの同じソースの読み取りをサポートするために、追加の長さを採用しています。dash
しません。zsh
、およびksh93
Debianのパッケージには、この上のBashで行きます。
sudo su
:unix.stackexchange.com/questions/218169/…–