Travis CIに似た非常にコンパクトなバージョンの関数を作成しようとしています。travis_retry
。関数は、デフォルトで指定された引数をコマンドで3回試行し、繰り返し失敗すると失敗(1を返す)する高次関数でなければなりません。
以下は私が試したいくつかの試みですが、それらのどれも私の期待に達していませんでした。
retry() {
"${@}" || "${@}" || "${@}"
}
これは単純なコマンド(例echo ciao
:)では機能しているように見えますが、重要な式では失敗します。
$ retry if true; then echo hello; fi; false
bash: syntax error near unexpected token `then'
私は関数がhello
3回印刷して返すことを期待しました1
(false
最後に評価されたので)。
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ですぐに使えます。