awkを介してリストを繰り返します。

awkを介してリストを繰り返します。

data.csvとlist.txtという2つのファイルがあります。以下は、彼らがどのように見えるかについての例です。

データ.csv:

"John","red","4"
"Basketball","orange","2"
"The Mike","blue","94"
"Lizard","purple","3"
"Johnny","pink","32"

リスト.txt:

Mike
John
purple
32

では、ループの作り方を知りたいです。

awk -F "\"*,\"*" '/**LIST ITEM**/ {print $1}' data.csv > output.txt

このコマンドは list.txt の各行に対して実行され、**LIST ITEM**を置き換えます。これはどのように達成できますか?

私はMacOSX 10.5.7で端末を介してこれを実行しています。

編集する:

上記の例の望ましい出力は次のとおりです。

The Mike
John
Johnny
Lizard
Johnny

編集2:

もっと明確に言えば、私は次のことを避けようとしています。

awk -F "\"*,\"*" '/Mike/ {print $1}' data.csv
awk -F "\"*,\"*" '/John/ {print $1}' data.csv
awk -F "\"*,\"*" '/purple/ {print $1}' data.csv
awk -F "\"*,\"*" '/32/ {print $1}' data.csv

代わりに、list.txtのすべての行を繰り返すコマンドで実行してください。

答え1

これは所望の出力順序と一致する。

$ awk -F, '
    NR == FNR {field1[$0] = $1; next}
    {
      for (line in field1) 
        if (line ~ $0) 
          print field1[line]
    }
  ' data.csv list.txt 
"The Mike"
"John"
"Johnny"
"Lizard"
"Johnny"

これは data.csv ファイルをメモリに読み込み、行全体を field1 にマップします。次に、list.txt ファイルの各行を field1 配列の各要素について確認します。

データファイルがリストファイルよりもはるかに大きい場合は、より小さなファイルをメモリに保持し、一度に1つずつ大きなファイルを繰り返す方が合理的です。

$ awk -F, '
    NR == FNR {list[$1]; next}
    {
      for (item in list) 
        if ($0 ~ item) 
          print $1
    }
  ' list.txt data.csv 
"John"
"The Mike"
"Lizard"
"Johnny"
"Johnny"

答え2

#!/bin/bash

 while read -r line; do 
   awk -F '^"|","|"$' '$0 ~ line{print $2}' line="$line" data.csv
 done < list.txt

概念の証拠

$ while read -r line; do awk -F '^"|","|"$' '$0 ~ line{print $2}' line="$line" data.csv; done < list.txt
The Mike
John
Johnny
Lizard
Johnny

このフィールド区切り文字は、埋め込まれた引用符および/またはコンマを処理します。

答え3

何をしたいのか完全には明確ではありません。アイテム一覧何?どこでも一致するものを見つけて最初のフィールドを出力しますか?また、あなたの例は行list.txtのどこでも一致しているように見え、これは問題になる可能性があります。list.txt行がどの点に含まれるとどうなりますかe?これは、例の最後の行を除くすべての項目と一致しますdata.csv

awk -F '^"?|"?,"?|"$?' 'BEGIN {
                          # read list.txt into an array
                          while (getline pat < "list.txt") {
                            pats[pat] = 1
                          }
                          close("list.txt")
                        }
                        {
                          # skip empty field before leading "
                          if ($1 == "") {
                            res = $2
                          } else {
                            res = $1
                          }
                          # scan record for patterns stored earlier,
                          # output the first real data field (res) if
                          # found
                          for (pat in pats) {
                            if ($0 ~ pat) {
                              print res
                            }
                          }
                        }' data.csv

これは思ったより少し複雑です。フィールド区切り文字は、最初のフィールドのオプションの先頭の引用符や最後のフィールドのオプションの後続の引用符を処理しません。私もそうですが、そこにあるコストのため、最初のフィールドは空になります(以前の空の文字列^"?)。また、埋め込まれた引用符を処理しようとしません。任意の一般的なCSVをサポートする必要がある場合は、専用のCSVパーサーを使用することをお勧めします。

関連情報