web-dev-qa-db-ja.com

他のコマンドのbashでforループ変数を使用する

次のタスクを計算するforループを実行したいと思います。awkを10回実行し、出力を合計して、最終結果を出力します。コードは以下に添付されています:

sum=0
for i in {1..10}
  do
  count=`awk '{if ($NF==$i) {print $NF}}' * | wc -l`
  sum=$[sum+count]
  echo $sum
done

問題は、私が変更した場合、$NF==$iから$NF==1の場合、結果は正しいですが、forループを使用して10回実行したいと思います。

コードの問題は何ですか?

3
9f241e21

ここでの問題は、単一引用符' ... '内でシェル変数の展開を取得しようとしていることです。ただし、一重引用符内では、Shell変数の展開が一時停止されます(例 this answer hereまたは Lhunath&GreyCat'sを参照) Bash Guide )、これが実際に推奨される理由です。$は、個々の入力フィールドを逆参照するときにawkで同様の機能を実行します(ただし、フィールド番号は、変数名も同様に、たとえば$NF)のように、プログラムを単一引用符で囲むと、「変数の展開」が同時に発生するのを回避できます。

あなたの場合、次のコマンドで値をawkプログラムに「インポート」できます

awk -v fieldnr="$i" '{if ($NF==fieldnr) {print $NF}}'

それでも、あなたの問題は完全にawkで解決できるように見えるので、達成したいことをより詳細に説明したいと思うかもしれません。よりエレガントな(そしておそらくより高速な)方法を見つけようとすることができます。別の質問を開くのは理にかなっているかもしれませんが...

4
AdminBee

awkですべてを行う方が効率的です。

awk -v n=0 '
  {for (i = 1; i <= 10; i++) if ($NF == i) {n++; break}}
  END {print n}' ./*

または、最後のフィールドが常に整数の場合:

awk -v n=0 '
  $NF >= 1 && $NF <= 10 {n++}
  END {print n}' ./*

または、比較を字句にして、123...、10の表現のみを許可する場合(01は不可) 、1e01.0...):

awk -v n=0 '
  $NF ~ /^([123456789]|10)$/ {n++}
  END {print n}' ./*
7

スクリプトが私が思っていることを実行する場合(つまり、一致する行のsumの増分値を1から10にループするときに出力します)、シェルスクリプトが生成する出力を生成するために必要なのは次のとおりです。

awk '
{ counts[$NF]++ }
END {
    for (i=1; i<=10; i++) {
        sum += counts[i]
        print sum
    }
}
' *

テストするサンプルの入力/出力を提供していないため、上記はテストされていません。

3
Ed Morton