ループを実行していて、COUNTER
を維持したい場合は、次のような単純なスクリプトがあります。カウンターが更新されていない理由がわかりません。それはサブシェルのthatsが作成されることによるものですか?どうすればこれを修正できますか?
#!/bin/bash
WFY_PATH=/var/log/nginx
WFY_FILE=error.log
COUNTER=0
grep 'GET /log_' $WFY_PATH/$WFY_FILE | grep 'upstream timed out' | awk -F ', ' '{print $2,$4,$0}' | awk '{print "http://domain.com"$5"&ip="$2"&date="$7"&time="$8"&end=1"}' | awk -F '&end=1' '{print $1"&end=1"}' |
(
while read WFY_URL
do
echo $WFY_URL #Some more action
COUNTER=$((COUNTER+1))
done
)
echo $COUNTER # output = 0
まず、あなたはカウンターを増やしていません。 COUNTER=$((COUNTER))
をCOUNTER=$((COUNTER + 1))
またはCOUNTER=$[COUNTER + 1]
に変更すると増加します。
第二に、あなたが推測するようにサブシェル変数を呼び出し先に逆伝播することはトリッキーです。サブシェル内の変数はサブシェル外では使用できません。これらは、子プロセスにとってローカルな変数です。
これを解決する1つの方法は、中間値を格納するための一時ファイルを使用することです。
TEMPFILE=/tmp/$$.tmp
echo 0 > $TEMPFILE
# Loop goes here
# Fetch the value and increase it
COUNTER=$[$(cat $TEMPFILE) + 1]
# Store the new value
echo $COUNTER > $TEMPFILE
# Loop done, script done, delete the file
unlink $TEMPFILE
COUNTER=1
while [ Your != "done" ]
do
echo " $COUNTER "
COUNTER=$[$COUNTER +1]
done
テスト済みBASH:Centos、SuSE、RH
COUNTER=$((COUNTER+1))
現代のプログラミングではかなり不器用な構成です。
(( COUNTER++ ))
もっと "モダン"に見えます。また使用することができます
let COUNTER++
読みやすさが向上すると思われる場合時々、Bashはあまりにも多くのやり方でやり方をします - 私が思うにPerlの哲学 - おそらくPythonが「それをするためのただ一つの正しい方法がある」がより適切かもしれないとき。それがあったとしても、それは議論の余地のある声明です!とにかく、(この場合の)目的は単に変数を増やすことではなく、他の誰かが理解してサポートできるコードを書くことであることをお勧めします。適合性は、それを達成するのに大いに役立ちます。
HTH
count=0
base=1
(( count += base ))
使ってみる
COUNTER=$((COUNTER+1))
の代わりに
COUNTER=$((COUNTER))
この単一のawk呼び出しはあなたのgrep|grep|awk|awk
パイプラインと同等であると思います。それをテストしてください。あなたの最後のawkコマンドは何も変わらないようです。
COUNTERの問題点は、whileループがサブシェル内で実行されているため、サブシェルが終了すると変数への変更がすべて失われることです。同じサブシェルでCOUNTERの値にアクセスする必要があります。または@ DennisWilliamsonのアドバイスを受けて、プロセスの置き換えを使用し、サブシェルを完全に避けてください。
awk '
/GET \/log_/ && /upstream timed out/ {
split($0, a, ", ")
split(a[2] FS a[4] FS $0, b)
print "http://example.com" b[5] "&ip=" b[2] "&date=" b[7] "&time=" b[8] "&end=1"
}
' | {
while read WFY_URL
do
echo $WFY_URL #Some more action
(( COUNTER++ ))
done
echo $COUNTER
}
一時ファイルを使用する代わりに、プロセス置換を使用してwhile
ループの周りにサブシェルを作成することを避けることができます。
while ...
do
...
done < <(grep ...)
ところで、そのgrep, grep, awk, awk, awk
をすべて単一のawk
に変換できるはずです。
Bash 4.2以降では、以下のようなlastpipe
オプションがあります。
現在のシェルコンテキストでパイプラインの最後のコマンドを実行します。ジョブ制御が有効になっている場合、lastpipeオプションは効果がありません。
bash -c 'echo foo | while read -r s; do c=3; done; echo "$c"'
bash -c 'shopt -s lastpipe; echo foo | while read -r s; do c=3; done; echo "$c"'
3
ミニマリスト
counter=0
((counter++))
echo $counter
これがあなたがする必要があるすべてです:
$((COUNTER++))
これはbashシェルの学習、第3版、147、148ページからの抜粋です。
bash算術式は、JavaおよびC言語の対応するものと同等です。優先順位と結合性はCと同じです。表6-2に、サポートされている算術演算子を示します。これらの中には特殊文字(または含む)もありますが、それらは$((...))構文内にあるため、円記号をエスケープする必要はありません。
..........................
++および - 演算子は、値を1つ増減する場合に便利です。[11]これらはJavaやCと同じように動作します。例えば、value++はvalueを1つ増加させます。これはと呼ばれます。インクリメント後; プリインクリメント:++値もあります。違いは例で明らかになります。
$ i=0
$ echo $i
0
$ echo $((i++))
0
$ echo $i
1
$ echo $((++i))
2
$ echo $i
2
http://www.safaribooksonline.com/a/learning-the-bash/7572399/ を参照してください。
counter
がスクリプトであることを更新しなかったようです。counter++
を使用してください