実行時にユーザーを切り替えるスクリプトを作成し、ファイルリダイレクトをstdinとして使用して実行しました。だからuser-switch.sh
......
#!/bin/bash
whoami
sudo su -l root
whoami
これを実行すると、bash
私が期待する動作が表示されます。
$ bash < user-switch.sh
vagrant
root
sh
ただし、次のようにスクリプトを実行すると、
$ sh < user-switch.sh
vagrant
vagrant
bash < user-switch.sh
与えられた出力がと異なるのはなぜですかsh < user-switch.sh
?
メモ:
- Debian Jessieを実行している2つの異なるコンピュータで発生しました。
ベストアンサー1
同様のスクリプト、no sudo
、しかし同様の結果:
$ cat script.sh
#!/bin/bash
sed -e 's/^/--/'
whoami
$ bash < script.sh
--whoami
$ dash < script.sh
itvirta
使用すると、bash
スクリプトの残りの部分が入力として使用され、シェルによって解釈されます。sed
dash
strace
次から実行:dash
スクリプトの塊(ここではスクリプト全体を入れるのに十分な8kB)を読み、次のように生成します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
。 (スクリプト長がブロックサイズ8kBを超えると、残りは読み取られます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
いいえ。 Debian にパッケージされておりzsh
、ksh93
Bash と一緒に使用されます。