親シェルhere-documentはdashのサブコマンドとは機能しませんが、bashが機能するのはなぜですか?

親シェルhere-documentはdashのサブコマンドとは機能しませんが、bashが機能するのはなぜですか?

dash私はdebianstretchで実行しており、次のコマンド(および)はすべてbashbashに入力されます。決してユーザーとして実行されない
ようですwhoamiテスト以下のコードのようにダッシュで表示されます。

$ sudo dash << 'end'
> su test
> whoami
> end
root
$ sudo bash << 'end'
> su test
> whoami
> end
test

ベストアンサー1

次の例を考えてみましょう。

$ cat f
grep pos /proc/self/fdinfo/0
IFS= read -r var
echo A
echo B
printf '%s\n' "var=$var"
$ bash < f
pos:    29
B
var=echo A
$ dash < f
pos:    85
A
B
var=

ご覧のとおり、コマンドを実行すると、stdinの場所はファイルgrepの終わりで、dashコマンドの後に続く改行文字の直後にあります。grepbash

コマンドecho Aはによって実行されますが、dashその場合bashは入力として与えられますread

dashコマンドを実行する前に、入力全体(実際にはテキストブロック)を一度に1行ずつ読みます。bash

これを行うには、bash改行文字を通過しないように一度に1バイトずつ読み込む必要がありますが、入力が通常のファイルである場合(上記のファイルの場合と同じでドキュメントにも適用されfます)、ここでbashはパイプのdash使用中に一時ファイルにします。実装します。 Linuxでわかるbashように、チャンクで読んで行末に逆追跡して最適化します。strace

$ strace -e読み取り、lseek bash < f
[...]
lseek(0, 0, SEEK_CUR) = 0
読み取り (0, "grep pos /proc/self/fdinfo/0\nIFS"...,85) = 85
lseek(0, -56, SEEK_CUR) = 29
ポジション:29
[...]

$strace -e 読み込み、lseek ダッシュ < f
読み取り (0, "grep pos /proc/self/fdinfo/0\nIFS"...,8192) = 85
ポジション:85
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=12422, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
読み取り(0,"",1) = 0
[...]

stdinがターミナルデバイスの場合、それぞれはread()ターミナルから送信された行を返すため、通常とbash同様の動作を見ることができますdash

あなたの場合は、次のようにすることができます。

sudo dash << 'end-of-script'
su test <<"end"
whoami
end
end-of-script

またはより良い:

sudo sh -c '
  su test -c whoami
'

または、より良い方法は次のとおりです。

sudo -u test whoami

おすすめ記事