簡単な解決策

簡単な解決策

次のファイルがあります

header start
stuff
header end
pos LV file LVG size
1   a1 AAA  BBB 100
2   b1 AAC  BBB 1000
3   a3 AAB  BBB 47
4   b6 AAC  BBB 1000

a2番目の列から始まる行数を数える必要があります。 Googleでこれを見つけました。

awk '/LVG/{p=$0} {a[p]++} END{for(i in a) print i"\n"a[i]-1}' file

ただし、出力が行数にすぎないようにコンテンツをフィルタリングする必要があります。以下を追加しました。

awk '/LVG/ || $2 ~ "^a"' file | awk '/LVG/{p=$0} {a[p]++} END{for(i in a) print i"\n"a[i]-1}' | tail -1

awkこれが私に必要な作業ですが、これらすべてが1つのコマンドで実行できるかどうか疑問に思います。

答え1

最も基本的な要件は次のとおりです。

awk '$2~/^a/{c++} END{print c+0}'

2番目の列をチェックし、正規表現の比較で始まることを確認し、aカウンタを増やしますc。ファイルの最後にカウンタが印刷されます。実際に増加しない数字も印刷されることを保証するために、すでにゼロ以外のc場合はc+0変更されないと印刷しますが、まだ初期化されていない場合は数字として解釈されるようにします。cc

「ヘッダー」セクションを妨げる「残る」トークンがないことを確認するために、最初のチェックは最初の列が整数であることを確認することです。

awk '$1+0==$1 && $2~/^a/{c++} END{print c+0}'

ここでのアイデアは、数値の場合は$1+0算術的に「何も追加しない」と解釈されますが、$1awk文字を追加0「テキスト」の場合、$1+0数値の場合にのみ変更されます。$1

より複雑なチェックのために行をすぐにスキップするだけでなく、「ヘッダーの終わり」行が表示されるまで行が考慮されないようにすることもできます。

awk 'f==2&&$2~/^a/{c++} f==1&&NF{f++} $0=="header end"{f=1} END{print c+0}'

行が見つかると、フラグはf1に設定され、ヘッダーの後の空でない最初の行に設定され、2番目の列が検証される行にのみ設定されます。header end2f2

答え2

私が提案するのはawk解決策ではなく、grepレコード構造に頼ることです。

$ grep "^[0-9]\+[[:blank:]]\+a[0-9]\+[[:blank:]]\+[A-Z]\+[[:blank:]]\+[A-Z]\+[[:blank:]]\+[0-9]\+$" file | wc -l
2

答え3

awk 'NR==1 ,/^header end$/ { next };
    !skip_hdr              { skip_hdr=1; next }
    ($2 ~ /^a/)            { count++ }
END{ print count+0 }' infile
  • NR==1 ,/^header end$/ { next }
    ファイルの先頭から最初の行に移動しますheader end。これは次の行をスキップします。

    ヘッダーの開始
    もの
    頭と尾
    

  • !skip_hdr { skip_hdr=1; next }:
    ヘッダー行をスキップpos LV file LVG size

  • ($2 ~ /^a/) { count++ }:2番目の列が文字で始まる行数を
    計算します(大文字と小文字を区別しません)。a

  • END{ print count+0 }
    最終カウント値を印刷します。

答え4

簡単な解決策

説明と一致:2番目の列から始まる行数の計算これで十分です。

awk '$2 ~ /^a/ { count++ } END {print count}' file 

grep(より速くする必要がある)コマンドを使用することもできます。

grep -c '^[0-9][0-9]* *a' test.txt

これはまた、最初のフィールドが数値(公開された例では必要なものであると仮定)であり、フィールド区切り文字が空白でなければならないという点でより具体的です。

もっと深く見る

ただし、公開した最初のソリューションは次のとおりです。

awk '/LVG/{p=$0} {a[p]++} END{for(i in a) print i"\n"a[i]-1}' file

全く違うことをしました。

このファイルに次のように入力します。

> cat file
header start
stuff
header end
pos1 LV file LVG size
1   a1 AAA  BBB 100
2   b1 AAC  BBB 1000
3   a3 AAB  BBB 47
4   b6 AAC  BBB 1000
5   c9 BBA  CBA 20
pos2 LV file LVG size
1   a1 AAA  BBB 100
2   b1 AAC  BBB 1000
pos3 LV file LVG size
1   a1 AAA  BBB 100
2   b1 AAC  BBB 1000
3   a3 AAB  BBB 47

公開したコードは、各(他の)ヘッダーの結果を印刷します。

> awk '/LVG/{p=$0} {a[p]++} END{for(i in a) print i"=="a[i]-1}' test.txt 
==2
pos1 LV file LVG size==5
pos3 LV file LVG size==3
pos2 LV file LVG size==2

つまり、空のタイトルに2行、タイトル「pos1」の後に5行など...

このような計算が必要かどうかわかりません。カウントから1を引く理由も不明です。

唯一の追加要件は、2番目のフィールドのみを計算することです。a

$ awk '/LVG/{p=$0} $2 ~ /^a/ {a[p]++} END{for(i in a) print i"=="a[i]}' test.txt
pos1 LV file LVG size==2
pos3 LV file LVG size==2
pos2 LV file LVG size==1

最初のフィールドも数値でなければならない場合(上記のgrepコマンドに似ています):

$ awk '/LVG/{p=$0} ($1+0!=0)&&($2~/^a/) {a[p]++} END{for(i in a) print i"=="a[i]}' test.txt
pos1 LV file LVG size==2
pos3 LV file LVG size==2
pos2 LV file LVG size==1

関連情報