web-dev-qa-db-ja.com

Bashループ内で変数をインクリメントする

ログファイルのエントリをカウントする小さなスクリプトを作成しようとしています。また、ループの完了後に使用しようとしている変数(USCOUNTER)をインクリメントしています。

しかし、その瞬間、USCOUNTERは実際の値ではなく0に見えます。私が間違っていることを知っていますか?ありがとう!

FILE=$1

tail -n10 mylog > $FILE

USCOUNTER=0

cat $FILE | while read line; do
  country=$(echo "$line" | cut -d' ' -f1)
  if [ "US" = "$country" ]; then
        USCOUNTER=`expr $USCOUNTER + 1`
        echo "US counter $USCOUNTER"
  fi
done
echo "final $USCOUNTER"

以下を出力します:

US counter 1
US counter 2
US counter 3
..
final 0
40
maephisto

サブシェルでUSCOUNTERを使用しているため、メインシェルに変数が表示されません。

cat FILE | while ...の代わりに、while ... done < $FILEを実行します。この方法で、 パイプラインにあるループに変数を設定します。ループが終了した後に変数が消えるのはなぜですか?または、データをパイプで読み取れないのはなぜですか?

while read country _; do
  if [ "US" = "$country" ]; then
        USCOUNTER=$(expr $USCOUNTER + 1)
        echo "US counter $USCOUNTER"
  fi
done < "$FILE"

また、 ``式を$()に置き換えました。

また、while read line; do country=$(echo "$line" | cut -d' ' -f1)while read country _に置き換えました。これにより、while read var1 var2 ... varNが残りのコンテンツを含むvar1まで、$var2が行の最初の単語、$varNなどを含むように言うことができます。

43
fedorqui
  • 常に-r with readを使用
  • cutを使用する必要はありません。純粋なbashソリューションを使用できます。
    • この場合、readに2番目の変数(_)を渡して、追加の「フィールド」をキャッチします
  • [[ ]]よりも[ ]を優先
  • 算術式 を使用します。
  • quote variables !を忘れないでください!リンクには他の落とし穴も含まれています
while read -r country _; do
  if [[ $country = 'US' ]]; then
    ((USCOUNTER++))
    echo "US counter $USCOUNTER"
  fi
done < "$FILE"

ミニマリスト

counter=0
((counter++))
echo $counter
14
geekzspot

final 0はサブ(シェル)プロセスで実行されており、そこで行われた変更は現在の(親)シェルに反映されないため、while loopを取得しています。

正しいスクリプト:

while read -r country _; do
  if [ "US" = "$country" ]; then
        ((USCOUNTER++))
        echo "US counter $USCOUNTER"
  fi
done < "$FILE"
13
anubhava

Whileループで同じ$ count変数を使用すると、問題が発生します。

@ fedorqui's answer (および他のいくつか)は、実際の質問に対する正確な答えです。サブシェルは確かに問題です。

しかし、それは私を別の問題に導きました:ファイルコンテンツをパイプしていませんでした...しかし、一連のパイプとgrepsの出力...

私のエラーサンプルコード:

count=0
cat /etc/hosts | head | while read line; do
  ((count++))
  echo $count $line
done
echo $count

そして、このスレッドの助けと プロセス置換 のおかげで私の修正

count=0
while IFS= read -r line; do
  ((count++))
  echo "$count $line"
done < <(cat /etc/hosts | head)
echo "$count"
6
jobwat
USCOUNTER=$(grep -c "^US " "$FILE")
2
Walter A

次の1行コマンドを使用して、フレーズの特異性を使用してLinuxで多くのファイル名を変更します。

find -type f -name '*.jpg' | rename 's/holiday/honeymoon/'

拡張子が「.jpg」のすべてのファイルについて、文字列「holiday」が含まれている場合は、「honeymoon」に置き換えます。たとえば、このコマンドはファイル名を「ourholiday001.jpg」から「ourhoneymoon001.jpg」に変更します。

この例では、findコマンドを使用して、拡張子が.jpg(-name '* .jpg')のファイルのリスト(-type f)を送信し、パイプ(|)で名前を変更する方法も示しています。 renameは、標準入力からファイルリストを読み取ります。

0
thanh

変数のインクリメントは次のように実行できます。

  _my_counter=$[$_my_counter + 1]

列内のパターンの出現回数をカウントするには、grepを使用します。

 grep -cE "^([^ ]* ){2}US"

-cカウント

([^ ]* )コロンを検出するには

{2}コロン番号

USあなたのパターン

0
trax