このパッケージがそのDebianアーカイブ(.deb)ファイルから解凍される前にスクリプトが実行するこの preinst ファイルの内容を調べています。
スクリプトのコードは以下のとおりです。
#!/bin/bash
set -e
# Automatically added by dh_installinit
if [ "$1" = install ]; then
if [ -d /usr/share/MyApplicationName ]; then
echo "MyApplicationName is just installed"
return 1
fi
rm -Rf $HOME/.config/nautilus-actions/nautilus-actions.conf
rm -Rf $HOME/.local/share/file-manager/actions/*
fi
# End automatically added section
私の最初の質問はラインについてです:
set -e
スクリプトの残りの部分は非常に単純だと思います。Debian/ Ubuntuパッケージマネージャがインストール操作を実行しているかどうかをチェックします。もしそうなら、それは私のアプリケーションがちょうどシステムにインストールされたかどうかをチェックします。もしあれば、スクリプトは "MyApplicationNameはインストールされました" というメッセージを表示して終了します(return 1
は「エラー」で終わることを意味しますか?).
ユーザがDebian/Ubuntuパッケージシステムに自分のパッケージをインストールするように要求している場合、スクリプトは2つのディレクトリも削除します。
これは正しいですか、私は何かが足りないのですか?
help set
から:
-e Exit immediately if a command exits with a non-zero status.
しかし、それはいくつかの人によって悪い習慣と考えられています(bash FAQとirc freenode #bash FAQ作者)。それを使用することをお勧めします:
trap 'do_something' ERR
エラーが発生したときにdo_something
関数を実行します。
コマンドまたはパイプラインにエラーがある場合、set -e
はスクリプトの実行を停止します。これは、シェルのデフォルトの動作(スクリプト内のエラーを無視すること)の反対です。この組み込みコマンドの資料を参照するには、端末にhelp set
と入力してください。
bash - The Set Builtin manualによると、-e
/errexit
が設定されている場合、 パイプライン が単一の 単純コマンド 、 リスト または 複合コマンド は0以外のステータスを返します。
デフォルトでは、パイプラインの終了ステータスは、pipefail
オプションが有効になっていない限り(デフォルトでは無効になっています)、パイプラインの最後のコマンドの終了ステータスです。
そうである場合、パイプラインは最後(一番右)のコマンドのステータスをゼロ以外のステータスで返します。すべてのコマンドが正常に終了した場合はゼロを返します。
終了時に何かを実行したい場合は、以下のようにtrap
を定義してみてください。
trap onexit EXIT
ここでonexit
は終了時に何かをするための関数です。以下のように単純な スタックトレース を出力します。
onexit(){ while caller $((n++)); do :; done; }
同様のオプション -E
/errtrace
があり、代わりにERRをトラップします。例えば:
trap onerr ERR
ゼロステータスの例:
$ true; echo $?
0
ゼロ以外の状況の例
$ false; echo $?
1
否定的なステータス例:
$ ! false; echo $?
0
$ false || true; echo $?
0
pipefail
を無効にしてテストします。
$ bash -c 'set +o pipefail -e; true | true | true; echo success'; echo $?
success
0
$ bash -c 'set +o pipefail -e; false | false | true; echo success'; echo $?
success
0
$ bash -c 'set +o pipefail -e; true | true | false; echo success'; echo $?
1
pipefail
を有効にしてテストします。
$ bash -c 'set -o pipefail -e; true | false | true; echo success'; echo $?
1
Googlingでこの質問を見つけました。set -e
が原因で中止されたスクリプトの終了ステータスが何であるかを見つけようとしました。答えは私には明白に見えませんでした。それ故にこの答え。基本的に、set -e
はコマンド(シェルスクリプトなど)の実行を中止し、失敗したコマンドの終了ステータスコード(つまり、外部スクリプトではなく内部スクリプト)を返します。
たとえば、シェルスクリプトouter-test.sh
があるとします。
#!/bin/sh
set -e
./inner-test.sh
exit 62;
inner-test.sh
のコードは次のとおりです。
#!/bin/sh
exit 26;
コマンドラインからouter-script.sh
を実行すると、外側のスクリプトが内側のスクリプトの終了コードで終了します。
$ ./outer-test.sh
$ echo $?
26
その意図は、問題のスクリプトが早く失敗することだと私は信じています。
これを自分でテストするには、単純にbashプロンプトでset -e
を入力してください。それでは、ls
を実行してみてください。ディレクトリ一覧が表示されます。それでは、lsd
と入力してください。そのコマンドは認識されずエラーコードを返すので、あなたのbashプロンプトは閉じます(set -e
のため)。
さて、これを「スクリプト」の文脈で理解するために、この単純なスクリプトを使用してください。
#!/bin/bash
# set -e
lsd
ls
そのまま実行すると、最後の行のls
からディレクトリの一覧が表示されます。 set -e
のコメントを外して再度実行した場合、bashがlsd
からのエラーに遭遇すると処理が停止するため、ディレクトリのリストは表示されません。
これは昔からの質問ですが、ここでの答えはどれもDebianパッケージ処理スクリプトでのset -e
またはset -o errexit
の使用について議論しているものではありません。これらのスクリプトでは、このオプションの使用は 必須 Debianポリシーに準拠しています。その意図は明らかに未処理のエラー状態の可能性を回避することです。
これが実際に意味することは、あなたが実行するコマンドがどのような条件の下でエラーを返すかもしれないかを理解しなければならず、そしてそれらの各エラーを明示的に扱うということです。
一般的な問題はdiff
(違いがあるとエラーを返します)とgrep
(一致がないとエラーを返します)。明示的な処理でエラーを回避できます。
diff this that ||
echo "$0: there was a difference" >&2
grep cat food ||
echo "$0: no cat in the food" >&2
(また、現在のスクリプトの名前をメッセージに含め、診断メッセージを標準出力ではなく標準エラーに書き出すように注意してください。)
明示的な処理が本当に必要でも有用でもない場合は、明示的に何もしないでください。
diff this that || true
grep cat food || :
(シェルの:
no-opコマンドの使用は少しあいまいですが、かなり一般的に見られます。)
繰り返しますが
something || other
の省略形です
if something; then
: nothing
else
other
fi
つまり、other
が失敗した場合に限り、something
が実行されるべきであると明示的に言います。省略形のif
(およびwhile
、until
などの他のシェルフロー制御ステートメント)もエラーを処理するための有効な方法です(実際にそうでない場合は、set -e
を持つシェルスクリプトにフロー制御ステートメントを含めることはできません)。
また、明示的に言うと、このようなハンドラーがない場合、diff
に違いが見つかった場合、またはgrep
に一致が見つからなかった場合、set -e
によってスクリプト全体が直ちにエラーで失敗します。
一方、いくつかのコマンドでは、必要なときにエラー終了ステータスを生成しません。一般的に問題のあるコマンドはfind
(終了ステータスはファイルが実際に見つかったかどうかを反映しない)とsed
(終了ステータスはスクリプトが入力を受け取ったか実際にコマンドを正常に実行したかを明らかにしません)です。いくつかのシナリオでの簡単な保護は、出力がない場合に悲鳴を上げるコマンドにパイプすることです。
find things | grep .
sed -e 's/o/me/' stuff | grep ^
パイプラインの終了ステータスは、そのパイプラインの最後のコマンドの終了ステータスです。そのため、上記のコマンドは実際にはfind
とsed
のステータスを完全に隠し、grep
が最後に成功したかどうかだけを示します。
(もちろん、Bashはset -o pipefail
を持っています;しかしDebianパッケージスクリプトはBash機能を使うことができません。これらのスクリプトにPOSIXのsh
を使うことをポリシーがしっかりと定めていますが、いつもそうとは限りません。)
多くの場合、これは防御的にコーディングするときに注意することです。時にはあなたがする必要があります。一時ファイルを調べて、その出力を生成したコマンドが、慣用句や便利さからシェルパイプラインを使用するように指示された場合でも、正常に終了したかどうかを確認できます。
Script 1: without setting -e
#!/bin/bash
decho "hi"
echo "hello"
This will throw error in decho and program continuous to next line
Script 2: With setting -e
#!/bin/bash
set -e
decho "hi"
echo "hello"
# Up to decho "hi" Shell will process and program exit, it will not proceed further