
しばらく待ってから、ディレクトリに複数のファイルがあるかどうかを確認する2つの条件があります。これらの条件の1つがtrueの場合、ループを実行する必要があるため、これは通常のOR論理文です。
予想される動作は、時間が経過した場合、またはディレクトリに複数のファイルがある場合、ループが終了することを意味します。 1 つ以上の文書がまだ待機中です。誰かが私のwhileループが期待どおりに機能しない理由を説明できますか?
i=1; while [ $i -le 10 ] || [ $( ls /opt/hosts/ | wc -l ) -lt 2 ]; do sleep 3 $(( i++ )); done
残念ながら、1行のコマンドが必要です。私のコマンドは、なぜORが期待どおりに機能しない無限ループなのかを知りたいのです。 (最初の条件を3に変更しました。)
+ echo host_name
+ i=1
+ '[' 1 -le 2 ']'
+ sleep 1 1
+ '[' 2 -le 2 ']'
+ sleep 1 2
+ '[' 3 -le 2 ']'
++ ls /opt/hosts/
++ wc -l
+ '[' 1 -lt 2 ']'
+ sleep 1 3
+ '[' 4 -le 2 ']'
++ ls /opt/hosts/
++ wc -l
+ '[' 1 -lt 2 ']'
+ sleep 1 4
+ '[' 5 -le 2 ']'
++ ls /opt/hosts/
++ wc -l
+ '[' 1 -lt 2 ']'
+ sleep 1 5 ```
答え1
sleep
2つのパラメータを提供3
します$(( i++ ))
。 GNUツールの場合、これはループするたびにループが休止状態にある時間(秒)が増加することを意味します。 GNU以外のシステムではsleep
。ループは常に実行されます少なくともテストの作成方法に応じて10回。テストに「
$i
10以下の繰り返し」と表示されます。 10に達すると、$i
テストの他の部分が適用されます。ここでは、ORの代わりに論理ANDテストを実行できます。ls | wc -l
ディレクトリ内のファイル数を計算するために使用しないでください。いくつかの(病理学的ですが)、これは誤った結果をもたらす可能性があります。
代わりに:
i=1
while [ "$i" -ne 10 ]; do
set -- /opt/hosts/*
if [ "$#" -ge 2 ]; then
break
fi
sleep 3 # or, to sleep longer and longer: sleep "$(( 3 + i ))"
i=$(( i + 1 ))
done
これはi
各反復ごとに適切に増加し、ディレクトリの名前数を数えるより安全な方法を使用します/opt/hosts
(ディレクトリ内のglobを拡張し、名前の*
数を数えることによって)。名前の数が2つ以上ある場合、$i
または値が10に達するたびにループが終了します。
ループ後$i
10の場合、ファイルはマテリアライズされていません。
位置引数(コマンドでオーバーライドset
)を保持する必要がある場合は、代わりにglobを配列に展開してnames=( /opt/hosts/* )
から"${#names[@]}"
その配列の長さを取得します"$#"
。
また、書くことができます
i=1
while [ "$i" -ne 10 ] && ( set -- /opt/hosts/*; [ "$#" -lt 2 ] )
do
sleep 3
i=$(( i + 1 ))
done
set
これは、サブシェルで実行されている既存の場所引数を削除しません。また、自分で試してみたタイプに近いです。
「一行」で:
i=1; while [ "$i" -ne 10 ]; do set -- /opt/hosts/*; [ "$#" -ge 2 ] && break; sleep 3; i=$(( i + 1 )); done
または「算術for
ループ」を使用してくださいbash
。
for (( i=1; i<=10; i++ )); do set -- /opt/hosts/*; [ "$#" -ge 2 ] && break; sleep 3; done
または、区切り線の上の最後のコード部分を使用してください。
i=1; while [ "$i" -ne 10 ] && ( set -- /opt/hosts/*; [ "$#" -lt 2 ] ); do sleep 3; i=$(( i + 1 )); done