最初のフィールドが重複している行のみを印刷しようとしています。たとえば、次のようなデータから:
1 abcd
1 efgh
2 ijkl
3 mnop
4 qrst
4 uvwx
印刷する必要があります:
1 abcd
1 efgh
4 qrst
4 uvwx
(FYI - 私のデータでは、最初のフィールドが常に 1 文字であるとは限りません)
awk 'FNR==NR{a[$1]++;next}(a[$1] > 1)' ./infile ./infile
はい、入力と同じファイルを 2 回指定します。現在のレコードが uniq かどうかは事前にわからないため、最初のパスに基づいて配列を構築し、2 番目のパスで複数回$1
見たレコードのみを出力します。$1
ファイルを1回通過するだけでそれを行う方法があると確信していますが、それらが「クリーン」になるとは思えません
FNR==NR
awk
: これは、 が最初のファイルを読み取っている場合にのみ当てはまります。基本的に、表示されたレコードの総数 (NR) と現在のファイルの入力レコード (FNR) をテストします。a[$1]++
: 連想配列を作成します。whoのキーは最初のフィールド ( $1
) であり、who の値は表示されるたびに 1 ずつ増加します。next
: これに達した場合、残りのスクリプトを無視し、新しい入力レコードからやり直します(a[$1] > 1)
これは の 2 回目のパスでのみ評価され、複数回見た./infile
最初のフィールド ( ) のレコードのみが出力されます。$1
本質的に、それはの省略形ですif(a[$1] > 1){print $0}
$ cat ./infile
1 abcd
1 efgh
2 ijkl
3 mnop
4 qrst
4 uvwx
$ awk 'FNR==NR{a[$1]++;next}(a[$1] > 1)' ./infile ./infile
1 abcd
1 efgh
4 qrst
4 uvwx
入力がすでに最初のフィールドでグループ化されていると仮定して、必要なことを行う awk コードを次に示します (required のようuniq
に):
BEGIN {f = ""; l = ""}
{
if ($1 == f) {
if (l != "") {
print l
l = ""
}
print $0
} else {
f = $1
l = $0
}
}
このコードでf
は、 はフィールド 1 の前の値でl
あり、グループの最初の行です (既に出力されている場合は空です)。
BEGIN { IDLE = 0; DUP = 1; state = IDLE }
{
if (state == IDLE) {
if($1 == lasttime) {
state = DUP
print lastline
} else state = IDLE
} else {
if($1 != lasttime)
state = IDLE
}
if (state == DUP)
print $0
lasttime = $1
lastline = $0
}
質問に示されているように、順序付けされた入力を想定します。
awk '$1 == prev {if (prevline) print prevline; print $0; prevline=""; next} {prev = $1; prevline=$0}' inputfile
ファイルは 1 回だけ読み取る必要があります。