sed、awk、grep、wc を使用して bash ループをフォーマットする方法

sed、awk、grep、wc を使用して bash ループをフォーマットする方法

特定の行を抽出し、特定の列の数字の出現回数をカウントする必要があるテキスト ファイルがあります。このようなファイルは 100 個ほどあります。小さなステップで実行できますが、bash/ksh を使用して実行したいと考えています。

foreach i *h3
sed '4p;55p;77q;d' $i >> output.txt
end 

^^^^これは各h3ファイルから必要な行を抽出するだけです

awk '{print $6}' output.txt | grep 'P2' | wc -l

^^^これはoutput.txtから列6を抽出し、列6にP2が出現する回数をカウントします。

これらすべてを bash/ksh スクリプトに組み合わせる方法はありますか?

答え1

私が正しく理解していれば:

  • いくつかのファイル (*h3) の 4、55、77 行目の 6 番目のフィールド内のどこかに "P2" が何回あるかを数えたいですか?

1 つの awk でこれを行うことができます:

awk '
( FNR==4 || FNR==55 || FNR==77 ) {
    if ( $6 ~ "P2" ) { occurence++ } 
}
END {
    printf "There was: %d P2 ", occurence
    printf " among the 6th field on lines 4,55 or 77 of the *h3 files\n"
}' *h3

注:完全一致が必要な場合は$6 ~ "P2"に変更してください$6 == "P2"(自分の例で使用した grep ではなく、次のように変更すると、:somethingP2otherthingおよびその変形にも一致します)

FNR = ファイルのレコード数 = 現在のファイルの行数 (つまり、各ファイルの最初の行で再び 1 から始まります) (現在のファイルの名前は、内部変数 FILENAME でも確認できます)

(NR = はここでは機能しません。これは、現在のファイルの最初からではなく、最初から読み取られたレコードの (合計) 数であるためです)

答え2

はい。これが一つの方法です

p2_count=0
for f in *h3; do
    for ((n=1; n<=77; n++)); do
        IFS= read -r line
        if [[ $n == 4|55|77 ]]; then
            echo "$line"
            set -f
            set -- $line
            set +f
            if [[ $6 == *P2* ]]; then
                ((p2_count++))
            fi
        fi
    done < "$f"
done > output.txt
echo "saw P2 in 6th column $p2_count times"

答え3

または、バッシュ一発ギャグ:

for i in *h3; do sed '4p;55p;77q;d' $i | awk '{print $6}' | grep 'P2'; done | wc -l

または、次のように短くしますgrep -c:

for i in *h3; do sed '4p;55p;77q;d' $i | awk '{print $6}'; done | grep -c 'P2'

答え4

通常、「大量のテキストファイルを処理するにはどうすればよいですか?」という質問がある場合、特定のツール「bash ループで実行しますか?」という質問に対する答えは、一部では「bash ループを使用せず、ツール自体 (の一部またはすべて) を使用してください」です。場合によっては、答えの一部には「それらのツールを使用せず、代わりにこれを使用してください」とさえあります。

必要なことはawk単独で実行でき、シェルループは必要ありません。またはsedまたはgrepまたはwc:

awk 'BEGIN {OFS="\t"}
     FNR ~ /^(4|10|17)$/ && $6 ~ /P2/ {count++}
     ENDFILE { print FILENAME, count; count=0 }' *h3

注記:終了ファイル は GNU に固有のものですawk。他のバージョンの では動作しませんawk

このバージョンでは、すべてのファイルの累積合計も出力されます。

awk 'BEGIN {OFS="\t"}
     FNR ~ /^(4|10|17)$/ && $6 ~ /P2/ {count++; total++}
     ENDFILE { print FILENAME, count; count=0 }
     END { print "---", total,"total" }' *h3

このEND{}ブロックは合計を出力し、また、ファイル名が「total」であるファイルと実際の合計を区別しようと大雑把に試みます。これは、---最初のフィールドに出力し、次に合計を出力し、3 番目のフィールドに文字列を出力します。これは完璧とは程遠いですが、多くの場合は十分です。 のように、まったく試みないtotalよりはましです。wc

関連情報