AWK: CSV ファイルをマージし、特定の値を含む行を削除するにはどうすればよいですか?

okwaves2024-01-25  8

何百もの CSV ファイルがあります。各 CSV ファイルは次のようになります。

| KEYWORD | NUMBER OF COMPS | AVGE M E (K) | GS/M | EST. A SE/M | C CORE |
|---------|-----------------|--------------|------|-------------|--------|
| Apples  | 311             | 12           | N/A  | <100        | 10     |
| Bananas | >1,200          | 737          | N/A  | 490         | 88     |
| Oranges | 48              | 184          | N/A  | N/A         | 1      |
| Fruits  | 161             | 94           | N/A  | -           | 6      |

(読みやすくするために、これを表形式で投稿しましたが、CSV データはこの投稿の下部にあります)。

すべての CSV ファイルには同じヘッダー行があります。データのみが異なります。

次のことを実行したいと考えています。

すべての CSV ファイルを結合しますが、ヘッダー行は 1 行だけです。 EST の行は省略します。 SE/M (列 5) には、次のデータのいずれかが含まれます: <100、N/A、または - データに関する注意事項 CSV ファイル内の一部またはすべてのセルが引用符で囲まれる場合があります。 そうでない場合もあります。 場合によっては、最初の列 (キーワード) に複数の単語またはアクセント付き文字が含まれることがあります。 これまでの私のコード

このコードは、すべての CSV ファイルを 1 つのファイルにマージします。ディン

awk '(NR == 1) || (FNR > 1)' *.csv > ^0-output.csv

これは完全に機能します。

しかし、マージ後に不要な行を削除する方法がわかりません。 これまでのところ、私はこれを持っています:

awk ' !~ /(<100|N\/A|-)/' ^0-output.csv > ^0-output.csv

しかし、このコードを使用すると、空のファイルが生成されるだけです。 さらに、これを最初の行に統合する方法があるかどうかもわかりません。そのため、単一のコマンドですべてを実行できます。

ノート データは CSV 形式でどのように表示されるかは次のとおりです

サンプル 1.csv

KEYWORD,NUMBER OF COMPS,AVGE M E (K),GS/M,EST. A SE/M,C CORE
Apples,311,12,N/A,<100,10
Bananas,">1,200",737,N/A,490,88
Oranges,48,184,N/A,N/A,1
Fruits,161,94,N/A,-,63

サンプル 2.csv

KEYWORD,NUMBER OF COMPS,AVGE M E (K),GS/M,EST. A SE/M,C CORE
Dino,588,67,N/A,888,234
Thunder,">1,200",211,N/A,<100,77
Ninja,95,37,N/A,-,878

サンプル 3.csv

KEYWORD,NUMBER OF COMPS,AVGE M E (K),GS/M,EST. A SE/M,C CORE
Blur,84,2454,N/A,-,234

サンプル 4.csv

"KEYWORD","NUMBER OF COMPS","AVGE M E (K)","GS/M","EST. A SE/M","C CORE"
"hedgehog rolls ròund",32,481,N/A,"878",13
"Clever Fox jumps Hîgh",233,83,N/A,"<100",12
"Bear à lot",122,35,N/A,"-",11
"kitten hîgh life","121","673","32","N/A","15"

注意: 完成したスクリプトが使用される実際のファイルには、さまざまなファイル名が付けられます。サンプル 1、サンプル 2 などのパターンに常に従うわけではありません。

期待される出力

期待される出力: (CSV 形式)

KEYWORD,NUMBER OF COMPS,AVGE M E (K),GS/M,EST. A SE/M,C CORE
Bananas,">1,200",737,N/A,490,88
Dino,588,67,N/A,888,234
"hedgehog rolls ròund",32,481,N/A,"878",13

(注: 期待される出力が wra を維持するかどうかは関係ありません最終的な CSV ファイルが Apple Numbers で開かれるときに引用符を押します)

期待される出力: (読み取り可能な形式)

| KEYWORD | NUMBER OF COMPS | AVGE M E (K) | GS/M | EST. A SE/M | C CORE |
|---------|-----------------|--------------|------|-------------|--------|
| Bananas | >1,200          | 737          | N/A  | 490         | 88     |
| Dino    | 588             | 67           | N/A  | 888         | 234    |
| hedgehog rolls ròund    | 588             | 67           | N/A  | 888         | 234    |

環境: Mac OS X 10.14.6を使用しています。他のバージョンの awk をインストールできません。



------------------------

&& を使用して、2 つのマージ条件を 1 つに追加するだけです。 :

awk -F, 'NR==1 || (FNR>1 &&  !~ /^(<100|N\/A|-)$/)' *.csv > output.csv

ここで $5 !~ /^(<100|N\/A|-)$/) は、$5 が <100 または - または N/A の場合に行をスキップします。 1000 や AB-123 などの不要な文字列との一致を避けるために、正規表現アンカー ^ と $ を使用することが重要です。

file1.csv にも二重引用符で囲まれたカンマがあるようです。その場合、次の gnu-awk コマンドが機能するはずです。

awk -v FPAT='"[^"]*"|[^,]*' '
NR == 1 || (FNR > 1 &&  !~ /^(<100|N\/A|-)*$/)' *.csv > output.csv

1

この議論はチャットで続けましょう。

– アヌバヴァ

2020 年 9 月 3 日 14:34



------------------------

編集: OPのコメントによると、「」の間にカンマがある可能性があります。そのため、これを処理するには、GNU awk で作成およびテストされた FPAT を使用する方が良いでしょう。

awk -v FPAT='[^,]*|"[^"]+"'  '
{ sub(/\r$/,"") }
FNR==1{
  if(NR==1){ print }
  next
}
=="<100"||=="N/A"||=="-"{
  next
}
1
' *.csv

示されているサンプルのみについて、GNU awk を使用して以下の記述とテストを試していただけますか。

awk '
BEGIN{
  FS=OFS=","
}
FNR==1{
  if(NR==1){ print }
  next
}
=="<100"||=="N/A"||=="-"{ next }
1
'  *.csv

または、値に他の値も含めることができ、無視したい値と一致させるために正規表現を使用したい場合は、次のことを試してください。

awk '
BEGIN{
  FS=OFS=","
}
FNR==1{
  if(NR==1){ print }
  next
}
~/<100/ || ~/N\/A/ || ~/-/{ next }
1
'  *.csv

説明: 上記の詳細な説明を追加します。

awk '                                        ##Starting awk program from here.
BEGIN{                                       ##Starting BEGIN section of this program from here.
  FS=OFS=","                                 ##Setting field separator as comma here.
}
FNR==1{                                      ##Checking condition if its firt line of current Input_file then do following.
  if(NR==1){ print }                         ##If its very first line of very first Input_file then print that line.
  next                                       ##next will skip all further statements from here.
}
=="<100"||=="N/A"||=="-"{ next }       ##Checking condition if 5th field contains either <100 OR N/A OR - then skip all further statements.
1                                            ##awk'sh way to print the current line.
'  *.csv                                     ##Passing all .csv files to awk program from here.

1

この議論はチャットで続けましょう。

– 大きな笑顔

2020 年 9 月 3 日 14:48



------------------------

私にはそう見えます最後から 2 番目のフィールドのみをテストする必要があり、そのフィールドにも最後のフィールドにもカンマを含めることはできないため、各行の先頭からではなく末尾からフィールド番号を数えるだけで、それより前のフィールドに次の値が含まれているかどうかは気にしません。カンマかどうか。そう考えると、これは任意の awk を使用して機能します。

$ awk -F',' '(NR==1) || (FNR>1 && $(NF-1)!~/^"?(<100|N\/A|-)"?$/)' *.csv
KEYWORD,NUMBER OF COMPS,AVGE M E (K),GS/M,EST. A SE/M,C CORE
Bananas,">1,200",737,N/A,490,88
Dino,588,67,N/A,888,234
"hedgehog rolls ròund",32,481,N/A,"878",13

0

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。