outer.sh
:
ls -l /proc/$$/exe
coproc cat
./inner.sh
kill $!
inner.sh
:
ls -l /proc/$$/exe
set | grep COPROC || echo No match found
coproc cat
kill $!
を実行すると、./outer.sh
以下が印刷されます。
lrwxrwxrwx 1 joe joe 0 Jun 16 22:47 /proc/147876/exe -> /bin/bash
lrwxrwxrwx 1 joe joe 0 Jun 16 22:47 /proc/147879/exe -> /bin/bash
No match found
./inner.sh: line 3: warning: execute_coproc: coproc [147878:COPROC] still exists
COPROC
子にはとが設定されていないので、COPROC_PID
親の子が私にこの警告を与えることができるかどうかどうすればわかりますか?
#!/bin/bash
また、上部に追加するか、fromの代わりにinner.sh
呼び出すと警告が消えることがわかりました。 bashサブプロセスを介して実行されますが、なぜこれが変更されますか?bash ./inner.sh
./inner.sh
outer.sh
答え1
shebangを持たないスクリプトはPOSIX準拠のインタプリタとして解釈されますsh
。これは実際にPOSIXスクリプトを書くPOSIX方式です。 POSIX は shebang を指定しません。しかし、実際にshebangを使用する方が移植可能で安定しています。ここに良い例があります。
bashシェルはPOSIX shインタプリタです。 bash(一部のバージョン、一部のカスタムビルド、および一部の環境)は、実際に私が知っている唯一のFLOSSシェルです。認証済みランタイムは規制に準拠していますsh
(ランタイムではありませんbash
)。
shebangなしでスクリプトを実行すると、bashはexecve()
ENOEXECを返し、バイナリのように見えないことを確認し、それをサブファイルから解釈し、状態をデフォルト値にリセットして実行をシミュレートします。
ただし、これは、スクリプト自体がPOSIXモードで実行されていない限り(たとえば、それ自体で呼び出される場合など)、実行時にスクリプトがbash
POSIX shスクリプトではなくbashスクリプトとして解釈されることを意味します。bash
sh
$ cat a
alias uname='echo hi'
uname
$ zsh -c ./a
hi
$ sh ./a
hi
$ bash -c ./a
Linux
$ (exec -a sh bash -c ./a)
hi
呼び出し時にa
sh言語ではなく言語(エイリアスを無視)として解釈される方法を理解します。bash
bash
~$ strace -qqfe execve bash -c ./a
execve("/usr/bin/bash", ["bash", "-c", "./a"], 0x7fff0081a820 /* 66 vars */) = 0
execve("./a", ["./a"], 0x55b18b3a4660 /* 66 vars */) = -1 ENOEXEC (Exec format error)
[pid 123559] execve("/usr/bin/uname", ["uname"], 0x55b18b3a4660 /* 66 vars */) = 0
Linux
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=123559, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
解釈スクリプトをbash
実行しない方法を参照してください。sh
あなたが得る事実warning: execute_coproc: coproc [147878:COPROC] still exists
はバグであり、bash
その状態を正しくリセットすることはできません。
とにかく、coproc
これはキーワードではないsh
ため、shebang-lessスクリプトではプレースメントはありません。実装はまったく異なりますが(そしてセカンダリプロセスはkshから来ます)、coproc
ここにShabanが必要です。zsh
bash
#! /bin/bash -
shebangを使用bash ./inner.sh
または使用すると、新しいインタプリタインスタンスが正しく実行され、execve()
プロセスメモリが完全に正しく消去されます。