説明する

説明する

次のテキストファイルがあります。

Doc_A 123 abc
Doc_A 456 def
Doc_A 789 ghi
Doc_B 123 abc
Doc_B 456 def
Doc_C 123 abc
Doc_C 456 def
Doc_C 789 ghi
Doc_C 101 jkl

と参考資料

Doc_A
Doc_B
Doc_C
Doc_D
Doc_E
Doc_F

参照ファイルの名前と一致するテキストファイルの最初の行を抽出し、その行を印刷するか、一致するものがない場合は、次のように特定の固定パターンを印刷したいと思います。

Doc_A 123 abc
Doc_B 123 abc
Doc_C 123 abc
Doc_D 10 20
Doc_E 10 20
Doc_F 10 20

以下のようにawkを使用して一致するパターンを印刷できます。要件に応じて固定された方法で見つからないパターンをどのように印刷できますか?

awk 'FNR == NR { a[$1] = 0; } FNR != NR { for (i in a) if ($0 ~ i && a[i]++ == 0) { print $0; break; } }' \ref.txt file.txt

答え1

一致するものをルックアップ配列から削除し、最後に残ったものを印刷するのはどうですか?

$ awk 'NR==FNR {a[$1]; next} 
  $1 in a {print; delete a[$1]} 
  END {for (i in a) print i, "10 20"}
' ref.txt file.txt
Doc_A 123 abc
Doc_B 123 abc
Doc_C 123 abc
Doc_D 10 20
Doc_E 10 20
Doc_F 10 20

(awkは配列巡回順序を保証しません。問題がある場合)

説明する

その間、NR==FNR私たちは最初の名前付きファイル(ref.txt)に取り組んでいます。最初の(この場合は一意の)フィールドにインデックス付きの配列エントリを作成し、レコードに移動しますnext。配列要素に値を割り当てる必要はありません。

それ以外の場合は、2番目の名前付きファイル()を処理していますfile.txt。最初の列が参照ファイルで構成した配列と一致することを確認し、a一致した場合はレコードを印刷します。$0その後、アイテムを削除します。

除去は2つの目的に使用される。次回$1 in a同じ項目をテストするとき、$1答えは偽になるため、一致を「固有」にします。これは、file.txtすべての行が処理された後でも、残りの要素がaまだ一致していないことを意味します。ENDこれをブロックの「固定」形式で印刷できます。

答え2

仕事にawkが必要ですか? grepも可能。

ファイルがスペースで区切られているようです。以下の解決策は、参照ファイルの固定パターンにスペースが含まれていないという前提に基づいています。

file.txtテキストファイルをref.txt

$ for P in $(cat ref.txt); do grep -m1 "^$P[[:blank:]]" file.txt || printf "%s 10 20\n" "$P"; done
Doc_A 123 abc
Doc_B 123 abc
Doc_C 123 abc
Doc_D 10 20
Doc_E 10 20
Doc_F 10 20

答え3

次のようなさまざまな方法でこれを実行できます。

awk '
 NR == FNR && !($1 in a){a[$1]=$0}
 NR != FNR{print ($1 in a) ? a[$1] : $1" 10 20"}
' inp ref.txt


perl -lane '
  $h{$F[0]} = $_ unless exists $h{$F[0]}}{
  while ( <STDIN> ) {
     chomp;
     print(exists $h{$_} ? $h{$_} : qq<$_ 10 20>);
   }
' inp < ref.txt


while IFS= read -r a
do
   grep -m1 -F -- "$a" inp || echo "$a 10 20"
done < ref.txt

結果:

Doc_A 123 abc
Doc_B 123 abc
Doc_C 123 abc
Doc_D 10 20
Doc_E 10 20
Doc_F 10 20

関連情報