A Quick Fixまではすべてスキップできますが、必ずしも最良のオプションではありません。だから私はこのすべてを最初に読むことを勧めます。
rc.local
エラーを許容しません。
rc.local
エラーからインテリジェントに回復する方法を提供しません。コマンドが失敗すると、実行が停止します。最初の行#!/bin/sh -e
により、-e
フラグで呼び出されたシェルで実行されます。-e
フラグが(この場合には、スクリプトを作るものであるrc.local
コマンドがその中に失敗した初めての実行を停止します)。
あなたはrc.local
このように振る舞います。コマンドが失敗した場合、他の起動コマンドが成功したことに依存している可能性のあるコマンドを続行したくありません。
したがって、いずれかのコマンドが失敗すると、後続のコマンドは実行されません。ここでの問題は、/script.sh
実行されなかったことです(失敗したことではなく、以下を参照)。しかし、どれですか?
でした/bin/chmod +x /script.sh
か?
いや
chmod
いつでも正常に動作します。を含むファイルシステム/bin
がマウントされていれば、を実行できます/bin/chmod
。そして、/bin
前に装着されてrc.local
実行されます。
rootとして実行した場合、/bin/chmod
失敗することはほとんどありません。操作対象のファイルが読み取り専用の場合は失敗し、そのファイルシステムがアクセス許可をサポートしていない場合は失敗する可能性があります。どちらもここにはありません。
ところで、sh -e
あるだけならば、それは実際に問題になる理由chmod
に失敗しました。インタープリターを明示的に呼び出してスクリプトファイルを実行する場合、そのファイルが実行可能とマークされているかどうかは関係ありません。/script.sh
ファイルの実行可能ビットが問題になると言われた場合のみ。それが言うのでsh /script.sh
、それは実行しません(もちろん、実行中にそれ/script.sh
自体を呼び出す場合、実行可能でないことから失敗する可能性がありますが、それ自体を呼び出す可能性は低いです)。
それで失敗したのは何ですか?
sh /home/incero/startup_script.sh
失敗しました。ほぼ間違いなく。
ダウンロードし/script.sh
たため、実行されたことがわかります。
(そうでなければ、それは場合には何らかの形で、それが実行しなかったことを確認することが重要であろう/bin
ではありませんでしたPATH - rc.local
必ずしも同じを持っていませんPATH
。あなたはログインしているときに持っているかのようには/bin
していなかったrc.local
のパス、この必要であろうsh
として実行する/bin/sh
。それは実行しなかったので、/bin
であるPATH
、あなたはに位置している他のコマンドを実行できることを意味し/bin
、完全に自分の名前を修飾せずに、たとえば、あなただけ実行することができますchmod
ではなく/bin/chmod
。しかし、あなたのスタイルに合わせてではrc.local
、実行をsh
提案するたびに、を除くすべてのコマンドに完全修飾名を使用しました。)
/bin/chmod +x /script.sh
絶対/script.sh
に実行されなかった(または実行されたことがわかります)と確信できます。そして、私たちsh /script.sh
はどちらも実行されなかったことを知っています。
しかし、ダウンロードしました/script.sh
。成功しました!どうして失敗するのでしょうか?
成功の2つの意味
コマンドが成功したと言ったときに人が意味する可能性のある2つの異なることがあります。
- あなたがやりたいことをやりました。
- 成功したと報告されました。
そしてそれは失敗のためです。コマンドが失敗したと人が言うとき、それは次のことを意味します。
- 望んでいたことをしませんでした。
- 失敗したと報告されました。
sh -e
などrc.local
で実行されるスクリプトは、コマンドが失敗したことを初めて報告したときに実行を停止します。コマンドが実際に行ったことに違いはありません。
あなたが望むことをするstartup_script.sh
ときに失敗を報告するつもりでない限り、これはのバグですstartup_script.sh
。
- いくつかのバグにより、スクリプトが望んでいることを実行できません。それらはプログラマが副作用と呼ぶものに影響します。
- また、いくつかのバグにより、スクリプトが成功したかどうかを正しく報告できません。これらは、プログラマがその戻り値(この場合は終了ステータス)を呼び出すものに影響します。
失敗したと報告された場合を除きstartup_script.sh
、必要なすべてのことを実行した可能性が最も高いです。
成功または失敗の報告方法
スクリプトは、ゼロ個以上のコマンドのリストです。各コマンドには終了ステータスがあります。スクリプトの実際の実行に障害がないと仮定すると(たとえば、インタープリターが実行中にスクリプトの次の行を読み取れなかった場合)、スクリプトの終了ステータスは次のとおりです。
0
(成功)スクリプトが空白の場合(つまり、コマンドがなかった場合)。
N
、スクリプトは、コマンドの結果として終了している場合、一部の終了コードです。exit N
N
- それ以外の場合は、スクリプトで実行された最後のコマンドの終了コード。
実行可能ファイルは、実行されると、それ自身の終了コードを報告します。スクリプト用だけではありません。(技術的には、スクリプトからの終了コードは、スクリプトを実行するシェルによって返される終了コードです。)
たとえば、Cプログラムがexit(0);
、またはreturn 0;
そのmain()
関数で終わる場合、コード0
はオペレーティングシステムに渡され、呼び出しプロセス(たとえば、プログラムが実行されたシェルなど)に提供されます。
0
プログラムが成功したことを意味します。1つおきの数字は、失敗したことを意味します。(このように、異なる数値は、プログラムが失敗したさまざまな理由を指す場合があります。)
失敗するコマンド
場合によっては、失敗することを意図してプログラムを実行します。これらの状況では、プログラムが失敗を報告するのはバグではありませんが、失敗は成功と考えるかもしれません。たとえば、rm
削除されたことを確認するためだけに、既に存在しないと思われるファイルで使用する場合があります。
このようなことはおそらくstartup_script.sh
、実行を停止する直前にで発生しています。実行するための最後のコマンドスクリプトではおそらく失敗を報告している(たとえその「失敗」完全に罰金、あるいは必要な場合があります)スクリプトレポートの失敗を行い、。
失敗するテスト
コマンドの特別な種類の1つはtestです。これは、副作用ではなく戻り値に対してコマンドを実行することを意味します。つまり、テストとは、終了ステータスを調査(および実行)できるように実行されるコマンドです。
たとえば、4が5に等しいかどうかを忘れるとします。幸いなことに、シェルスクリプトを知っています。
if [ 4 -eq 5 ]; then
echo "Yeah, they're totally the same."
fi
ここでは、[ -eq 5 ]
結局4≠5であるため、テストは失敗します。それは、テストが正しく実行されなかったことを意味しません。やった 4 = 5かどうかを確認し、そうであれば成功を報告し、そうでなければ失敗を報告するのが仕事でした。
シェルスクリプトでは、成功はtrueを意味し、失敗はfalseを意味することもあります。
にもかかわらず、echo
文が実行されることはありません、if
全体としてブロックは、リターンの成功を行います。
しかし、私はそれを短く書いたと仮定します:
[ 4 -eq 5 ] && echo "Yeah, they're totally the same."
これは一般的な略記法です。&&
あるブール とオペレータ。&&
で構成されて表現、&&
両側が真(成功)を返していない限りいずれかの側の声明で、偽(失敗)を返します。ただ、通常のようにして。
「デレクはモールに行って蝶のことを考えた?」と誰かが尋ねたら。デレクがモールに行かなかったことを知っているなら、彼が蝶のことを考えているかどうかを気にする必要はありません。
同様に、左側のコマンドが&&
失敗した場合(false)、&&
式全体がすぐに失敗します(false)。右側のステートメント&&
は実行されません。
ここで、[ 4 -eq 5 ]
実行します。「失敗」(falseを返す)。したがって、&&
式全体が失敗します。echo "Yeah, they're totally the same."
決して実行されません。すべてが正常に動作しましたが、このコマンドは失敗を報告します(if
上記の同等の条件が成功を報告した場合でも)。
それがスクリプト内の最後のステートメントである場合(およびスクリプトはその前のあるポイントで終了するのではなく、それに到達した場合)、スクリプト全体が失敗を報告します。
これ以外にも多くのテストがあります。たとえば、||
(「または」)を使用したテストがあります。ただし、上記の例はテストとは何かを説明するのに十分であり、ドキュメントを効果的に使用して特定のステートメント/コマンドがテストかどうかを判断できるようにする必要があります。
sh
vs. sh -e
、再訪
以来ライン(も参照この質問のトップに)持っている、それがコマンドで起動されたかのように、オペレーティングシステムは、スクリプトを実行します:#!
/etc/rc.local
sh -e
sh -e /etc/rc.local
対照的に、などの他のスクリプトはフラグなしstartup_script.sh
で実行されます。-e
sh /home/incero/startup_script.sh
その結果、それらのコマンドが失敗を報告しても、それらは実行し続けます。
これは正常で良いことです。他のほとんどのスクリプト(ほとんどのスクリプトを含む)rc.local
で起動する必要があります。sh -e
rc.local
違いを覚えておいてください:
スクリプトはsh -e
、コマンドに含まれるコマンドが最初に失敗を報告するときに、失敗を報告する出口で実行されます。
スクリプトは、スクリプト内のすべてのコマンドが&&
演算子で結合された単一の長いコマンドであるかのようです。
スクリプトを使用してsh
(なしで-e
)実行するスクリプトは、スクリプトを終了する(終了する)コマンドに到達するまで、またはスクリプトの最後まで実行し続けます。すべてのコマンドの成功または失敗は、本質的に無関係です(次のコマンドでチェックされない限り)。スクリプトは、最後に実行されたコマンドの終了ステータスで終了します。
結局のところ、スクリプトがそれほど失敗ではないことを理解するのに役立ちます
失敗したのに失敗したとスクリプトが考えないようにする方法はありますか?
実行が完了する直前に何が起こるかを確認します。
成功するはずのコマンドが失敗した場合は、その理由を見つけて問題を修正します。
コマンドが失敗し、それが正しいことだった場合、その失敗ステータスが伝播しないようにします。
失敗ステータスが伝播しないようにする1つの方法は、成功する別のコマンドを実行することです。/bin/true
副作用はなく、成功を報告します(/bin/false
何もせず、失敗もします)。
別の方法は、スクリプトがによって終了することを確認することexit 0
です。
これは、必ずしもexit 0
スクリプトの最後にあるのと同じではありません。たとえばif
、スクリプトが内部で終了する-blockが存在する場合があります。
成功を報告する前に、スクリプトが失敗を報告する原因を知ることが最善です。本当に何らかの方法で失敗した場合(やりたいことを実行しないという意味で)、成功を報告することは望ましくありません。
クイックフィックス
startup_script.sh
exitで成功を報告できない場合は、rc.local
それを実行するコマンドを変更して、成功startup_script.sh
しなかったとしてもコマンドが成功を報告するようにすることができます。
現在、次のものがあります。
sh /home/incero/startup_script.sh
このコマンドには同じ副作用(つまり、実行の副作用startup_script.sh
)がありますが、常に成功を報告します。
sh /home/incero/startup_script.sh || /bin/true
startup_script.sh
失敗を報告する理由を知り、修正することをお勧めします。
クイックフィックスの仕組み
これは実際には||
テスト、またはテストの例です。
あなたが私がゴミを取り出したのか、フクロウを磨いたのか尋ねるとします。ゴミを取り出したら、フクロウを磨いたかどうか覚えていなくても、「はい」と正直に言うことができます。
||
実行の左側のコマンド。成功した場合(true)、右側を実行する必要はありません。したがって、startup_script.sh
成功を報告すると、true
コマンドは実行されません。
ただし、[ゴミを出さなかった]startup_script.sh
という失敗が報告された/bin/true
場合、[フクロウをブラッシングした場合]の結果が重要になります。
/bin/true
常に成功を返します(またはtrueと呼ばれることもあります)。その結果、コマンド全体が成功し、次のコマンドをrc.local
実行できます。
成功/失敗、真/偽、ゼロ/非ゼロに関する追加の注記。
これを無視してください。ただし、複数の言語でプログラムを作成する場合(シェルスクリプトだけでなく)には、この記事を読むことをお勧めします。
Cなどのプログラミング言語を使用するシェルスクリプト作成者にとって、またシェルスクリプトを使用するCプログラマにとって、次のことを発見することは大きな混乱のポイントです。
シェルスクリプトの場合:
- 戻り値は、成功および/またはtrueを
0
意味します。
- 失敗やfalseを
0
意味する以外の戻り値。
Cプログラミングの場合:
- 戻り値
0
はfalse .. を意味します
- 以外の戻り値
0
はtrueを意味します。
- 何が成功を意味し、何が失敗を意味するかについての単純なルールはありません。
0
成功を意味する場合もあれば、失敗を意味する場合もあれば、追加したばかりの2つの数値の合計がゼロであることを意味する場合もあります。一般的なプログラミングの戻り値は、さまざまな種類の情報を通知するために使用されます。
- プログラムの終了ステータスの数値は、シェルスクリプトの規則に従って成功または失敗を示す必要があります。つまり
0
、Cプログラムではfalseを意味しますが、0
成功したことを報告する場合は、プログラムを終了コードとして返します(シェルはtrueとして解釈します)。