シェルスクリプトのコードスタイルはtry-Exceptionに似ています。

シェルスクリプトのコードスタイルはtry-Exceptionに似ています。

私はコンピュータでの日常的な作業を容易にするためにシェルスクリプトを学んでいます。
Pythonには例外処理のためのEAFPスタイル(「許可よりも許しを求める方が簡単です」)があります。

    >>> while True:
    ...     try:
    ...         x = int(input("Please enter a number: "))
    ...         break
    ...     except ValueError:
    ...         print("Oops!  That was no valid number.  Try again...")

このスタイルはシェルスクリプトで使用できますか?

ベストアンサー1

EAFPをどのように解釈するかによって異なります。狭い意味ではPythonが設計されていますが、一部の言語では不可能であり、他のほとんどの言語では一般的ではなく、強く推奨されない例外処理の使用を意味します。しかし、より広い意味では、EAFPはほとんどすべてのプログラミング言語、特にシェルスクリプトで一般的です。

私は仮定するPOSIX シェルスクリプト、少し注意を払う吹く。 Pythonコードの例はPython 3です。

許可の代わりに許しを求める方法はいくつかあります。

Pythonは二分法に最も密接に関連するプログラミング言語です。行動する前に考えなさい(LBYL)そして許可より許しを求める方が簡単です(EAFP)。 Pythonでは、EAFPは通常、LBYL方式のタスクを試みる前にタスクが成功するかどうかを確認するのではなく、例外が発生することを許可してそれをキャッチすることを意味します。

しかし、これが唯一の2つの可能性ではありません。失敗した場合は例外を発生させない操作を試すことができますが、試行後に失敗したことを確認し、結果に応じて他のアクションを取ることができます。例外処理を使用しないので、Pythonの観点からEAFPと呼ぶのは奇妙に感じますが、実際にはLBYLよりもEAFPとの共通点があります。この「EAFP」はシェルスクリプトで非常に一般的です。

Pythonの例から始めるのが役に立つと思います。これらの用語はPython文化と密接に関連しているだけでなく、EAFP、LBYL、および「EAFP」例外をPythonできれいで簡単な方法ですべて実証することができるためです。dタイプが次のと仮定しますdict

# EAFP
try:
    print(d['foo'])
except KeyError:
    print('Not found.')
# LBYL
if 'foo' in d:
    print(d['foo'])
else:
    print('Not found.')
# Exceptionless "EAFP"
v = d.get('foo')
if v is None:
    print('Not found.')
else:
    print(v)

調査する 推測するシェルコマンドが成功した場合:LBYL

時々、私たちはシェルスクリプトで単純なLBYLを使用します。このコードはDebianとUbuntuのデフォルトファイルに含まれており、.bashrcホームディレクトリに.bash_aliases。その場合は、これを取得しようとします(現在のシェルで各行をコマンドとして実行)。これは適用対象ですが、競争条件、この場合に発生したエラーは何の害もないので、これは非常に良いデザインの選択です。

if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

しかし、サブディレクトリに移動して、サブディレクトリの外で誤って実行したくないことをしたいとしましょう。少なくとも純粋な形のLBYLは悪い選択です。この場合、アクションは、1つに一致する複数のサブディレクトリから始まり、繰り返し削除することです。全体的な状況。 (...合理的なセキュリティを維持しながらこれを実行するためのさまざまな方法がたくさんあるため、これは少し工夫されています。必要に応じて、実行前および/または後にそのディレクトリにさらに多くの作業があると想像できます。rm

# Don't do it this way!
if [ -d drafts ] && [ -x drafts ]; then  # BAD!
    cd drafts                            # BAD!
    rm -r foo*                           # BAD!
fi                                       # BAD!

draftsここでは、ディレクトリの変更が成功したことを確認したいと思います。私はそれが存在し、ディレクトリであること(-d)、そしてそれに対する実行権限があることを-x確認しました()。 * nixシステムのディレクトリーに対して実行権限を使用すると、そのディレクトリーを変更できます。 (通常。)

この方法が非常に複雑であるという事実に加えて、問題は私が何かを逃したかもしれないということです。何も変わらなくてもそれは本当ですか?保証するこのディレクトリに入ることができますか?全部確認しましたか?[これは読者の練習問題として残します。 ]

また、私がしても持つすべてをチェックし、ディレクトリが存在しアクセス可能であることを確認しました。以前は。この場合、競争条件は実際に重要です。何かが変更されてディレクトリに入ることができず、コマンドが失敗した場合は、その中に含まれるゴミのサブディレクトリではなく、共存するすべての貴重なcdサブディレクトリを削除します。foo*drafts

シェルコマンドを実行し、動作していることを確認してください。した成功:EAFP?

これらの考慮事項に注意してください。いくつかの理由PythonでEAFPを使用する:複雑なコードや読みにくいコードを使用しないでください。そして状況が変わる可能性のあるリスク〜サイ確認し、確認に従って対処してください。。実際、これは上記の誤ったアプローチよりも簡単で強力です。

if cd drafts; then
    rm -r foo*
fi

cd drafts特に、条件()が失敗した場合にすべてが失敗した終了状態になるようにしたい場合は、次のように書かれていることがわかります。

cd drafts && rm -r foo*

これは例外処理とリモートで同様のものを使用しません。しかし、飛躍する前には見えません。draftsディレクトリが存在し、アクセス可能かどうかは確認されません。ただそれを変えようと努力しているだけです。次に、試した後rm、成功したかどうかを確認し、そうでない場合はコマンドの実行を拒否し続けます。

EAFP が例外処理の使用を参照している場合、これは EAFP ではありません。比較が躊躇している場合、最終的にこのアプローチは例外処理の前からあり、Cなどの言語で一般的であることを理解しています。しかし、これは同じ目標のいくつかによって動機付けられており、同じ状況のほとんどに当てはまります。

もちろん、これは実際には比較的典型的なプログラミングから許しを求めることは許可の一形態ではありません。 Pythonは完全に一般的な状況でも例外を発生させるのを防ぎません(実際にはお勧めします)、まれです。

トラップはどうですか?

私もある程度同意するジャスの答え。シェルスクリプトのトラップは、実際にエラー(コマンド失敗の意味で)を処理する基本的な方法ではありませんが、Pythonの例外処理と多少似ています。

しかし、シェルスクリプトのトラップとPythonの例外の間には、いくつかの重要な実際の違いがあります。

  • Pythonプログラムは常に例外を使用します。ほとんどのシェルスクリプトはトラップをほとんど使用しません。
  • Python例外は通常、現在の実行スレッド内で発生します(常にそうではありませんが)。対照的に、トラップは通常非同期で実行され、他のプロセスやシステムから送信された信号(Ctrlユーザーが+を押すとSIGINT C)などの非同期イベントを処理するために主に使用されます。しかし、このような場合に限定されない。

トラップはシェルスクリプトの制御フローにはほとんど使用されず、他のオプションが利用可能な場合はエラー処理にはほとんど使用されません。コマンドを実行して動作していることを確認するには、確認できます。終了ステータス。上記のように、制御構造はifこれを行う方法を提供します。他の人もいます。)。

おすすめ記事