web-dev-qa-db-ja.com

Awkを使用して区切りファイルから特定の列を抽出する

これが基本的すぎる場合は申し訳ありません。列にヘッダー行(v1、v2など)があるcsvファイルがあります。 1列目と2列目を抽出するには、awk -F "," '{print $1 "," $2}' infile.csv > outfile.csv。しかし、たとえば列1から10、20から25、および30から33を抽出する必要がある場合はどうでしょうか。補遺として、列番号ではなくヘッダー名で直接抽出する方法はありますか?

32
user702432

Awkで範囲を実行できるかどうかはわかりません。 forループを実行できますが、不要な列を除外するための処理を追加する必要があります。これを行う方が簡単でしょう。

awk -F, '{OFS=",";print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$20,$21,$22,$23,$24,$25,$30,$33}' infile.csv > outfile.csv

考慮すべき他の何か-これはより速く、より簡潔です:

cut -d "," -f1-10,20-25,30-33 infile.csv > outfile.csv

質問の2番目の部分については、ヘッダー行の処理方法を知っているPerlでスクリプトを記述し、stdinまたはファイルから列名を解析してからフィルター処理を行うと思います。それはおそらく、私が他のもののために持ちたいツールです。私はそれができると確信していますが、私は1つのライナーで行うことについて確信がありません。

52
Cliff

@Tomで述べたように、cutとawkのアプローチは、引用符付きの文字列を含むCSVでは実際には機能しません。別の方法はpythonのモジュールです。これはコマンドラインツールcsvfilterを提供します。カットのように機能しますが、CSV列の引用を適切に処理します。

csvfilter -f 1,3,5 in.csv > out.csv

python(そしてそうする必要がある))がある場合は、次のように簡単にインストールできます。

pip install csvfilter

Csvfilterの列インデックスは0から始まることに注意してください(awkは$ 1から始まります)。詳細は https://github.com/codeinthehole/csvfilter/

13
studgeek

他の人があなたの以前の質問に答えました。このため:

補遺として、列番号ではなくヘッダー名で直接抽出する方法はありますか?

試したことはありませんが、各ヘッダーのインデックスをハッシュに保存し、後でそのハッシュを使用してインデックスを取得できます。

for(i=0;i<$NF;i++){
    hash[$i] = i;
}

その後、それを使用します:

j = hash["header1"];
print $j;
3
Ritesh

他の言語には、フィールド番号の範囲のショートカットがありますが、awkではありません。あなたの恐怖としてコードを書く必要があります;-)

awk -F, 'BEGIN {OFS=","} { print $1, $2, $3, $4 ..... $30, $33}' infile.csv > outfile.csv

Awkには、列指定子としてフィールド名を使用する直接関数はありません。

これがお役に立てば幸いです。

3
shellter

Forループを使用して、$ iでフィールドをアドレス指定できます。

ls -l | awk '{for(i=3 ; i<8 ; i++) {printf("%s\t", $i)} print ""}'
2

Tabulator は、ヘッダー行を持つcsvファイルを操作するためのUNIXコマンドラインツールのセットです。ファイルtest.csv:から名前で列を抽出する例を次に示します

name,sex,house_nr,height,shoe_size
arthur,m,42,181,11.5
berta,f,101,163,8.5
chris,m,1333,175,10
don,m,77,185,12.5
elisa,f,204,166,7

次にtblmap -k name,height test.csvが生成します

name,height
arthur,181
berta,163
chris,175
don,185
elisa,166
1
stefan.schroedl

Perlがオプションの場合:

_Perl -F, -lane 'print join ",",@F[0,1,2,3,4,5,6,7,8,9,19,20,21,22,23,24,29,32]'_

_-a_は、行を_@F_フィールド配列に自動分割します。インデックスは0から始まります(awkのように1ではありません)
_-F,_フィールド区切り文字は、

CSVファイルに引用符で囲まれたコンマが含まれている場合、Perlの_Text::CSV_XS_などの本格的なCSVパーサーは、そのような奇妙さを処理するために特別に構築されています。

Perl -MText::CSV_XS -lne 'BEGIN{$csv=Text::CSV_XS->new()} if($csv->parse($_)){@f=$csv->fields();print (join ",",@f[0,1,2,3,4,5,6,7,8,9,19,20,21,22,23,24,29,32])}'

私はここで私の答えの中でより多くの説明を提供しました: gawkを使用してcsvファイルを解析

0
Chris Koknat

Awkを使用していませんが、これを実現する最も簡単な方法は、単に csvtool を使用することでした。 csvtoolを使用する他のユースケースもあり、列データ自体に引用符または区切り文字が含まれている場合、それらを適切に処理できます。

csvtool format '%(2)\n' input.csv
csvtool format '%(2),%(3),%(4)\n' input.csv

2を列番号に置き換えると、探している列データが効果的に抽出されます。

0
Samar