これは私のスクリプトの一部です。
#!/bin/sh
n=1
echo "How many repetitions to run (0 = no limit)?"
read reps
if [ $reps = 0 ]; then
while="true"
else
while="[ $n -lt $((reps+1)) ]"
fi
echo "How much off-time in-between reps (in minutes)?"
read time
pwr_init
while $while; do
echo "* Sending power pulse $n"
pwr_normal
t=$time
echo "* Waiting for next power on"
while [ $t -gt 0 ]; do
echo " $t min until next power on"; sleep 60
t=$((t-1))
done
n=$((n+1))
done
while
私がやっている最初のループを除いて、すべてが私が望む方法で正確に機能しています。変数が呼び出されるたびに$while
シェルが展開され、最初のステートメントで定義されているthen変数を確認したいと思いますif
。
最初のステートメントから変数を拡張するシェルのみを取得できますが、コンパレータは常にtrueで、最初のステートメントの内容中に変数がすでに拡張されているため、増分したときに変更されないため、if
私が取得する動作です。true
$n
$while
if
${!while}
同様のアプローチと一重引用符と二重引用符のさまざまな組み合わせを試しましたが、運がありませんでした。通常$n is a bad number
、または同様のエラーが発生しますbad substitution
。
今私が考えることができる唯一のことは、より多くの関数により多くのステートメントを追加して、この行が毎回チェックされ、ステートメントに反映されるようif
にすることです。while
私はこれを行うより良い方法があると信じなければなりません。しかし、私はそれを見つけるのに苦労しています(オンラインで検索するための適切なキーワードを見つけるのも難しいです)。
デバッグ時に使用すると、set -x
コンパレータ文字列がここでスクリプト化された方法で正しく評価されていることがわかりますが、前述のように増加して$n
もそれ自体は更新されません。
このタイプの人生を少し簡単にする代替のヒントを持っている人はいますか?この奇妙な変数拡張の謎の洞察力を提供していただきありがとうございます!
注1:pwr_init
およびpwr_normal
は、スクリプト全体の他の場所で定義された関数です。
注2:Shebangに注意してください。 POSIXと互換性がなければなりません。クールなbash固有のスキルは利用できません。
編集:それがうまくいくのと同じようにうまくいくのは思ったより簡単でした。以下に追加した内容を入れました。しかし、このタイプの変数拡張が可能であれば知っておくと良いでしょうので、この質問は開いておきます。
新しいスクリプトのcheck
機能は、if
次の文に含まれています。
#!/bin/sh
n=1
echo "How many repetitions to run (0 = no limit)?"
read reps
count=$((reps+1))
check() {
if [ $reps = 0 ]; then
while="true"
else
while="[ $n -lt $count ]"
fi
}
echo "How much off-time in-between reps (in minutes)?"
read time
pwr_init
while $while; do
echo "* Sending power pulse $n"
pwr_normal
t=$time
echo "* Waiting for next power on"
while [ $t -gt 0 ]; do
echo " $t min until next power on"; sleep 60
t=$((t-1))
done
n=$((n+1))
check
done
答え1
非常に簡単な解決策:「無限に」実行するには、制限を非常に大きな数字に設定します。 32ビット整数は最大4294967296までの数字を保持できます。符号ビットを考慮し、下降すると、少なくとも2000000000まで数えることができると仮定することができる。数字を数える間に少なくとも1分間眠るので、これは約4000年間可能です。
だからこうしてください:
if [ "$reps" = 0 ]; then
reps=2000000000
fi
条件を次のようにハードワイヤーします。
while [ "$n" -le "$reps" ]; do ...
(64ビットシステムを実行している場合はより高く計算できますが、問題はありません。16ビットシステムを実行している場合は、おそらく他の方法で壊れます。)
簡単な解決策:reps
0よりn
小さいことを確認する関数を作成してくださいreps
。
keep_going() {
[ "$reps" = 0 ] && return 0
[ "$n" -le "$reps" ]
}
それから条件を出す
while keep_going; do ...
はい、毎回関数を呼び出しています。いいえ、最大1分に1回しか呼び出せないため、問題ありません。 (本当に速度に興味がある場合は、この作業にシェルを使用しないでください。)
あなたが探しているソリューション:使用eval
。ペアの割り当てに二重引用符を使用すると、while="[ $n -lt $count ]"
すべて$n
が$count
すぐに拡張されます。必要なのは、割り当てに一重引用符を使用することです。while='[ $n -lt $count ]'
次に、文字列を実行してeval
その中の変数を展開します。
while='[ $n -lt $count ]'
while eval "$while" ; do ...
答え2
他の関数を定義してみることができます。
if [ $reps -eq 0 ]; then
while_test() { true; }
else
while_test() { test $1 -lt $((reps+1)); }
fi
それから
while while_test $n; do
eval
POSIX シェルでは、以下を使用して変数の条件を処理できます。
$ cond='[ $n -lt $reps ]'
$ reps=5
$ n=4
$ eval "$cond" && echo 'n < reps' || echo 'n >= reps'
n < reps
$ n=5
$ eval "$cond" && echo 'n < reps' || echo 'n >= reps'
n >= reps
変数が早期に拡張されないように、条件が一重引用符で定義されていることを確認してください。