|| を使用して bash 関数演算子を圧縮し、コマンドを再試行してください。

|| を使用して bash 関数演算子を圧縮し、コマンドを再試行してください。

Travis CIに似た非常にコンパクトなバージョンの関数を作成しようとしています。travis_retry。関数は、デフォルトで指定された引数をコマンドで3回試行し、繰り返し失敗すると失敗(1を返す)する高次関数でなければなりません。

以下は私が試したいくつかの試みですが、それらのどれも私の期待に達していませんでした。

retry() {
    "${@}" || "${@}" || "${@}"
}

これは単純なコマンド(例echo ciao:)では機能しているように見えますが、重要な式では失敗します。

$ retry if true; then echo hello; fi; false
bash: syntax error near unexpected token `then'

私は関数がhello3回印刷して返すことを期待しました1false最後に評価されたので)。

2番目の試みは次のとおりです。

retry() {
    $* || $* || $*
}

これは以前と同じです。 3番目のバージョンも試しましたが、eval当然動作しません。この時点で、ここにいくつかの基本が欠けていることが明らかであるので、試してみるのではなく理解したいと思います。

答え1

関数を使用すると、複数の文字列引数のみを渡すことができるため、単純なコマンドの引数としてのみ解釈できます。任意のシェルコードを文字列として渡すことはできますが、関数にリテラル文字列として渡すためにコードを評価して引用する必要があります。

retry() { eval " $1" || eval " $1" || eval " $1"; }
retry 'if true; then echo hello; fi; false'

またはあなたのもの:

retry() { "$@" || "$@" || "$@"; }

と呼ばれる:

retry eval 'if true; then echo hello; fi; false'

ただし、エイリアスを使用すると、次のことができます。

alias 'retry{{={
  attempts=0
  until {' '}}=
  }; do
    if (( ++attempts >= 3 )); then
      echo >&2 "Giving up after $attempts attempts"
      ! break
    fi
  done
}'

それから:

bash-5.0$ retry{{ echo test; false; }}
test
test
test
Giving up after 3 attempts

これは、Cのプリプロセッサマクロのように、コードが完全に解析される前にコードを読み取るとエイリアスが拡張されるために機能します。

答え2

別のオプションは、bashの最初の原則の代わりに再試行コマンドを使用することです。

ここでは、毎回失敗して3回試行した後に放棄する重要でない式を再試行します。

~$ ./retry --times 3 -- sh -c "echo hello; echo there; false"
hello
there
retry: sh returned 1, backing off for 10 seconds and trying again...
hello
there
retry: sh returned 1, backing off for 10 seconds and trying again...
hello
there
retry: sh returned 1, backing off for 10 seconds and trying again...

https://github.com/minfrin/retry

最新のDebian、Ubuntu、Nixですぐに使えます。

関連情報