web-dev-qa-db-ja.com

bash +セカンダリスクリプトとメインスクリプトの両方を終了する方法

スクリプトを実行しますscript1スクリプトからscript_main

script_main

#!/bin/bash
/tmp/script1
echo $?

sleep 2
echo script ended 

script1

#!/bin/bash
exit 1

明らかなように、script1は終了コード1で終了しますが、メインスクリプトは最後まで続行されます。

私の質問:script1exit 1、次にmain_scriptすぐに停止しますか?

5
yael

最も簡単な方法は、他のスクリプトが失敗した場合に最初のスクリプトを明示的にexitにすることです。次のようにスクリプトを条件付きで実行します

otherscript.sh || exit 1

または

if ! otherscript.sh ; then
      ret=$?
      echo "otherscript failed with exit code $ret. exit." >&2
      exit 1
fi

これにより、メインスクリプトが必要なクリーンアップを実行したり、おそらく子の終了コードに応じて他の解決策を試したりできるようになります。最初のコードでは、|| exitだけを使用して、子の終了コードを渡すことができます。

anyコマンドが開始したときにメインスクリプトを終了させたい場合は、set -eを使用します。

set -e
otherscript.sh
echo "this will not run if otherscript fails"

set -eは、条件付き構文内で実行されるプログラムには適用されないため、特定のコードをテストしたり、|| trueを使用してコードをテールしたりして、失敗を無視できます。しかし、今やどこにでも出口点があるので、trap somecmd EXITを使用して、シェルが終了する前に、それがどこで発生するかに関係なく、クリーンアップを実行できます。


内部スクリプトがメインスクリプトを強制的に終了させることも可能ですが、やや不親切で、通常のアプリケーションがそれを実行するとは思わないでしょう。ただし、必要に応じて、内部スクリプトを単純に古いプロセスの親プロセスで実行させるのも1つの方法です。

$ cat mainscript.sh
#!/bin/bash
./otherscript.sh
echo "$0 exiting normally"
$ cat otherscript.sh
#!/bin/bash
echo "$0 kill $PPID"
kill $PPID

$ bash mainscript.sh
./otherscript.sh kill 11825
Terminated

ここで、インタラクティブシェルからotherscript.shを実行すると、インタラクティブセッションの撮影が試行されます。私がテストしたすべてのシェルは、対話的に実行している場合でも、この場合SIGTERMを無視するようです。いずれの場合でも、メインシェルは再びtrapSIGTERMを実行できます。

親プロセスだけを撮影する代わりに、kill 0を使用して、プロセスグループotherscript.shが実行されているすべてのプロセスを強制終了できます。非対話型シェルから開始した場合、通常は親が含まれます。

9
ilkkachu

script 2を入手できます。お気に入り:

. /tmp/script1.sh

そして終了コードがscript2から読み込まれ、プロセスが終了します。

➜  /tmp cat script.sh 
#!/bin/bash

echo "Running ${0} with pid $$"
. /tmp/script1.sh
echo $?
echo "This code won't execute"
sleep 2
echo "Script ${0} ended"
echo "This code won't execute"
sleep 2

echo "Script ${0} ended"



➜  /tmp cat script1.sh 
#!/bin/bash

echo "Running ${0} with pid $$"
exit 5

それを実行する:

➜  /tmp ./script.sh 
Running ./script.sh with pid 10306
Running ./script.sh with pid 10306
➜  /tmp echo $?
5
2
fugitive