2017-01-21 3 views
1

set -eの動作をエミュレートする方法を見つけることを試みていますが、その関数のスコープ内でのみです。Bash:エラーでの優雅な関数の破棄

基本的には、単純なコマンドでトリガーすると、set -eが1つ上のレベルを返す関数が必要です。目標は、危険な仕事の集合を機能に分けて、それらを適切に処理できるようにすることです。

答えて

3

コマンドを失敗させて1を返す場合は、各コマンドの後に|| return 1と入力してください。例えば

false || return 1 # This will always return 1 

私は明示的な取り扱いなしで失敗する任意のコマンドをさせることはないの大ファンです。私のスクリプトでは、戻りコードではない方法でエラーを返し、すべてのエラーをトラップする例外処理テクニックを使用しています(bashトラップで)。非ゼロの戻りコードを持つコマンドは、自動的に状況やバグが不適切に処理されたことを意味します。このような状況が発生するとすぐにスクリプトが失敗することを好みます。

+0

しかし、それはどちらもうまくいかない。これは私がエラーチェックを行う方法ではありません、私は最初にチェックしておくべきです。私の反応の一部を削除しました。 – Fred

+0

場合によっては、トラップを閉じ込める方がよい場合もあります。 –

+0

「トラップをトラップする」とはどういう意味ですか? – Fred

0

注意:この手法の使用を強くお勧めします。あなたがサブシェル環境でこの関数を実行すると、あなたはほとんどあなたが望む動作を得るでしょう。以下を検討してください:

#!/bin/bash 

foo() ( # Use parens to get a sub-shell 
     set -e # Does not impact the main script 
     echo This is executed 
     false 
     echo This should *not* be executed 
) 

foo # Function call fails, returns 1 
echo return: $? 

# BUT: this is a good reason to avoid this technique 
if foo; then # Set -e is invalid in the function 
     echo Foo returned 0!! 
else 
     echo fail 
fi 
false # Demonstrates that set -e is not set for the script 
echo ok 
+0

あなたは何をお勧めしますか? bashスクリプトのエラー処理は、体系的に(どこでも、何らかのフレームワークで、アドホックなアプローチではなく)実行するのに非常に苦労したことです。他の人たちがどうやってそれを行うのか不思議です。私はそれがどこでも深く議論されて見たことがありません。 – Fred

+0

'set -e'は例外処理に最も近いものですが、それは非常に原始的です。関数の中でクリーンアップを扱い、明示的に何らかの失敗(例えば 'cmd || return')を返すトラップを返すことができます。これはおそらくあなたが得ることができる最高のものです。 –

+0

bashサポートに関しては、yes set -eとtrapがほとんどありますが、エラー処理のサポートでは、処理されていないすべてのゼロ以外の戻りコードによってスクリプトが中止される例外処理メカニズムを構築できます。これは私が構築したものであり、長年のコードの信頼性という大きなメリットにもかかわらず、他の誰かがそのことを言及したことは一度もありませんでした。 – Fred

0

Javaが提供するものとやや同じように「ネストされた例外」を探しているようです。スコープを設定する必要がある場合は、機能の冒頭でset -eを実行し、set +eを実行してから戻ってください。

効率的または便利ではないもう一つのアイデアは、サブシェルであなたの関数を呼び出すことです:いずれの場合で

# some code 

(set -e; my_function) 
if [[ $? -ne 0 ]]; then 
    # the function didn't succeed... 
fi 

# more code 

set -eでエラーを処理しない最大の方法であることに注意してください。シェルスクリプト。あまりにも多くの問題が非常に信頼性の低いものになっています。これらの関連記事を参照してください。

私は本番環境で長い時間のために存在する必要がある大規模なスクリプトのために取るアプローチは次のとおりです。

  • 作成すべての標準のものを行うための関数のライブラリ
  • ライブラリにはラッパーaroun各標準的なアクション(例えば、mv,cp,mkdir,lnrmなど) -

:)慎重に引数を検証しても、例外時に例外

  • を処理することを、明確なエラーメッセージ
  • とラッパー終了終了自体は多少このように、ライブラリ関数かもしれません
    # library of common functions 
    
    trap '_error_handler' ERR 
    trap '_exit_handler' EXIT 
    trap '_int_handler' SIGINT 
    
    _error_handler() { 
        # appropriate code 
    } 
    # other handlers go here... 
    # 
    
    exit_if_error() { 
        error_code=${1:-0} 
        error_message=${2:-"Uknown error"} 
    
        [[ $error_code == 0 ]] && return 0 # it is all good 
    
        # this can be enhanced to print out the "stack trace" 
        >&2 printf "%s\n" $error_message 
    
        # out of here 
        my_exit $error_code 
    } 
    
    my_exit() { 
        exit_code=${1:-0} 
        _global_graceful_exit=1 # this can be checked by the "EXIT" trap handler 
        exit $exit_code 
    } 
    
    # simple wrapper for cp 
    my_cp() { 
        # add code to check arguments more effectively 
        cp $1 $2 
        exit_if_error $? "cp of '$1' to '$2' failed" 
    } 
    
    # main code 
    
    source /path/to/library.sh 
    
    ... 
    my_cp file1 file2 
    # clutter-free code 
    

    これは、ERREXITイベントに行動を起こすtrapの有効活用とともに、信頼性の高いシェルスクリプトを書くための良い方法だろう。

  • +0

    'set -e'は私の望むことに対して実際には全く機能しません。関数内に設定されていても、スクリプト全体が即座に中止されます。私はそのスクリプトを実行する前にそれを設定することと変わりありません。 http://pastebin.com/p84B5R8b – OstermanA

    +0

    ちょうど私の答えのサブシェルのアイデアを見てみましょう。確実に実行する必要があるものを書く場合は、 'set -e'はお勧めしません。 – codeforester

    +0

    あなたのexit_if_error関数は、私が望んでいたものではありません...しかし、それが意味をなさなくするほど、私はもっと見ています。本当の試行錯誤の仕組みがなければ、おそらく私ができることは最高です。 – OstermanA

    0

    もっと研究して、私はGoogleのShell Style Guideのような解決策を見つけました。ここではいくつか真剣におもしろい提案がありますが、私は可読性のためにこれを使用するつもりです:

    if ! mv "${file_list}" "${dest_dir}/" ; then 
        echo "Unable to move ${file_list} to ${dest_dir}" >&2 
        exit "${E_BAD_MOVE}" 
    fi 
    
    +0

    エコーの必要はありません。 'mv'はすでに素晴らしいエラーメッセージを出しています。 –

    +0

    合意。これは簡単な例です。はるかに有用なメッセージは、その機能が何であるか、なぜ失敗が致命的であるか、などです。 – OstermanA

    関連する問題