ディレクトリをループし、特定のパターンの横の値を合計して平均を生成します。

ディレクトリをループし、特定のパターンの横の値を合計して平均を生成します。

ディレクトリ内のすべてのファイルをループ処理したいです。

ファイルは次のように配置されます:

<Overall>4
other data
<Overall>2
other data
......

コードは以下のとおりです:

for file in .dat; 
do
awk 'x+=sub(/<Overall>/,""){y+=$0} END{print FILENAME, y/x}' $file
done

これはファイル内の値の平均を出力しますが、私が望んでいるのは、スクリプトがあるディレクトリを引数として取り、そのディレクトリ内のすべての .dat ファイルに対して awk コマンドを実行することです。

次のコードを使ってみました:

for file in $1

しかし、エラーが発生します:

awk: cmd. line:1: fatal cannot open file `folder' for reading (No such file or directory)

これに加えて、平均値の出力を高いものから低いものの順に並べ替えられるようにしたいと考えています。

答え1

2つのバリエーション:

  1. ファイルをループし、awk各ファイルごとに1回呼び出すか、
  2. スクリプトにすべてのファイルを与えawk、それぞれの平均を計算して、計算の進行に合わせてレポートを作成します。

以下のソリューションのいずれかの結果のソートは、出力をパイプすることで実行できます。

sort -k2,2rn

これにより、2 番目のフィールド (平均) で逆の数値ソートが実行されます。


最初の解決策:

#!/bin/sh

for name in "$1"/*.dat; do
    test -f "$name" || continue   # skip non-files
    awk -F '>' '/<Overall>/ { s+=$NF; n++ } END { print FILENAME, s/n }' "$name"
done

このスクリプトは、最初の、そして唯一のコマンドライン引数として、コマンドライン上のディレクトリ名を想定しています。スクリプトawkは、文字列 を含むすべての行を検索し、その行のの後の値をOverall( で) 合計します。最後に、平均がファイル名とともに出力されます。変数 には、に何かを追加した回数が保持されます。s>ns


2 番目の解決策 (GNU Awk が必要):

#!/bin/sh

find "$1" -maxdepth 1 -type f -name '*.dat' \
    -exec awk -F '>' '/<Overall>/ { s+=$NF; n++ } ENDFILE { print FILENAME, s/n; s=n=0 }' {} +

このスクリプトは、最初のスクリプトと同様に、唯一のコマンド ライン引数としてディレクトリ名を必要とします。これを使用して、一度にできるだけ多くのファイルでスクリプトfindを実行します。awk.dat

このスクリプトは、各ファイルを処理した後、次のファイルの読み取りを開始する前に、awkGNU Awk のENDFILEトリガーを使用して計算された値を出力し、変数sとをリセットします。n

これは次のようにも書かれるかもしれない。

#!/bin/sh

awk -F '>' '/<Overall>/ { s+=$NF; n++ } ENDFILE { print FILENAME, s/n; s=n=0 }' "$1"/*.dat

しかし、これは"$1"/*.datファイル名のリストが長くなりすぎないことに依存しています (また、各名前が通常のファイルである必要があり、これは上記のコマンドで保証されている.datものです)。find-type f

関連情報