web-dev-qa-db-ja.com

bash / kshのコマンドの終了コードを取得します

このようなコードを書きたい:

command="some command"

safeRunCommand $command

safeRunCommand() {
   cmnd=$1

   $($cmnd)

   if [ $? != 0 ]; then
      printf "Error when executing command: '$command'"
      exit $ERROR_CODE
   fi
}

しかし、このコードは私が望むようには機能しません。どこで間違えたの?

52
Kolesar

以下は修正されたコードです。

#!/bin/ksh
safeRunCommand() {
  typeset cmnd="$*"
  typeset ret_code

  echo cmnd=$cmnd
  eval $cmnd
  ret_code=$?
  if [ $ret_code != 0 ]; then
    printf "Error : [%d] when executing command: '$cmnd'" $ret_code
    exit $ret_code
  fi
}

command="ls -l | grep p"
safeRunCommand "$command"

このコードを見てみると、私が変更したいくつかの点は次のとおりです。

  • typesetの使用は必須ではありませんが、良い習慣です。 cmndおよびret_codesafeRunCommandに対してローカルにします
  • ret_codeを使用する必要はありませんが、戻りコードを何らかの変数に格納(およびできるだけ早く格納)して、printf "Error : [%d] when executing command: '$command'" $ret_codeで行ったように後で使用できるようにすることをお勧めします
  • safeRunCommand "$command"のようなコマンドを囲む引用符でコマンドを渡します。しない場合、cmndls -lではなく、値lsのみを取得します。また、コマンドにパイプが含まれている場合はさらに重要です。
  • スペースを保持する場合は、typeset cmnd="$*"の代わりにtypeset cmnd="$1"を使用できます。コマンド引数の複雑さに応じて、両方を試すことができます。
  • evalは、パイプを含むコマンドが正常に機能するように評価するために使用されます

注:grepのようなエラーが発生していなくても、一部のコマンドでは戻りコードとして1が指定されることを忘れないでください。 grepが何かを見つけた場合、0または1を返します。

KSH/BASHでテストしました。そして、それはうまくいきました。あなたがこれを実行している問題に直面するならば、私に知らせてください。

66
havexz

試して

safeRunCommand() {
   "$@"

   if [ $? != 0 ]; then
      printf "Error when executing command: '$1'"
      exit $ERROR_CODE
   fi
}
5
sehe

$($cmd)ではなく$cmdにする必要があります。私の箱のそれでうまくいきます。

編集:スクリプトは、lsなどの1ワードのコマンドに対してのみ機能します。 「ls cpp」では機能しません。これが機能するには、cmd="$1"; $cmd"$@"に置き換えます。また、スクリプトをcommand="some cmd"; safeRun commandとして実行するのではなく、safeRun some cmdとして実行します。

また、bashスクリプトをデバッグする必要がある場合は、「-x」フラグを使用して実行します。 [bash -x s.sh]。

2

スクリプトにはいくつかの問題があります。

関数(サブルーチン)は、呼び出す前に宣言する必要があります。おそらく、サブルーチンからexit()ではなくreturn()を使用して、呼び出しブロックが特定のコマンドの成功または失敗をテストできるようにする必要があります。それはさておき、「ERROR_CODE」をキャプチャしないため、常にゼロ(未定義)になります。

変数参照も中括弧で囲むことをお勧めします。コードは次のようになります。

#!/bin/sh
command="/bin/date -u"          #...Example Only

safeRunCommand() {
   cmnd="$@"                    #...insure whitespace passed and preserved
   $cmnd
   ERROR_CODE=$?                #...so we have it for the command we want
   if [ ${ERROR_CODE} != 0 ]; then
      printf "Error when executing command: '${command}'\n"
      exit ${ERROR_CODE}        #...consider 'return()' here
   fi
}

safeRunCommand $command
command="cp"
safeRunCommand $command
1
JRFerguson

通常のアイデアは、コマンドを実行し、$?を使用して終了コードを取得することです。ただし、終了コードを取得する必要がある場合が複数あります。たとえば、出力を非表示にしつつ、終了コードを返すか、終了コードと出力の両方を印刷する必要がある場合があります。

ec() { [[ "$1" == "-h" ]] && { shift && eval $* > /dev/null 2>&1; ec=$?; echo $ec; } || eval $*; ec=$?; }

これにより、終了コードが必要なコマンドの出力を抑制するオプションが提供されます。コマンドの出力が抑制されると、関数から終了コードが直接返されます。

個人的にこの関数を.bashrcファイルに入れたい

以下に、これを使用できるいくつかの方法を示します。


# In this example, the output for the command will be
# normally displayed, and the exit code will be stored
# in the variable $ec.

$ ec echo test
test
$ echo $ec
0

# In this example, the exit code is output
# and the output of the command passed
# to the `ec` function is suppressed.

$ echo "Exit Code: $(ec -h echo test)"
Exit Code: 0

# In this example, the output of the command
# passed to the `ec` function is suppressed
# and the exit code is stored in `$ec`

$ ec -h echo test
$ echo $ec
0

この関数を使用したコードの解決策

#!/bin/bash
if [[ "$(ec -h 'ls -l | grep p')" != "0" ]]; then
    echo "Error when executing command: 'grep p' [$ec]"
    exit $ec;
fi

また、表示される終了コードは、実行中の最後のコマンドであるため、実行中のgrepコマンド用であることにも注意してください。 lsではありません。

0
Nathan F.