bashファイルのリダイレクトは、Linuxの標準シェル( `sh`)とどう違うのですか?

bashファイルのリダイレクトは、Linuxの標準シェル( `sh`)とどう違うのですか?

実行時にユーザーを切り替えるスクリプトを作成し、ファイルリダイレクトを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スクリプトの残りの部分が入力として使用され、シェルによって解釈されます。seddash

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 にパッケージされておりzshksh93Bash と一緒に使用されます。

おすすめ記事