私はUnixに慣れていない非常に大きなCSVファイルを扱っています。
例は次のとおりです。
ABC1,ABC2,ABC3,DDD,EEE,FFF
1,2,3,4,5,6
1,2,3,4,5,6
で始まるすべての列を抽出する方法はABC
?
答え1
次のawk
プログラムはそのトリックを実行します。次のファイルに保存しますextract.awk
。
#!/bin/awk -f
BEGIN { FS=OFS=","}
FNR==1 {
for (i=1;i<=NF;i++) {
if (index($i,startstr)==1) cols[++ncol]=i;
}
}
{ for (j=1;j<=ncol;j++) printf("%s%s",$(cols[j]),j==ncol?ORS:OFS) }
それから電話してください。
~$ awk -f extract.awk -v startstr="ABC" input.csv
ABC1,ABC2,ABC3
1,2,3
1,2,3
文字列を検索する変数の位置を定義しますstartstr
。
これにより、まず入力フィールドと出力フィールドの区切り文字がに設定されます,
。
- 最初の行(ヘッダー行)は、変数に格納されている検索文字列で始まる列名があることを確認します
startstr
。その場合、列番号がcols
「印刷する列」配列に追加されます。 - 各行(最初の行を含む)に対して保存されているすべての列の値を印刷し、最後の列の
cols
場合は、フィールド区切り文字またはレコード区切り文字(デフォルトは改行)を印刷します。
実際の検索文字列に正規表現コンテキストに特殊文字が含まれている場合、使用する関数は正規表現ベースの一致ではindex()
なく文字通りの文字列一致を実行します。awk
正規表現の基本検索を使用する必要がある場合は、以下を変更してください。
if (index($i,startstr)==1) cols[++ncol]=i;
到着
if ($i ~ startstr) cols[++ncol]=i
ただし、その中のすべての文字はstartstr
正規表現トークンとして解釈されるため、注意しないと予期しない動作が発生する可能性があります。言及した例startstr
の場合^ABC
。
答え2
awkを使用してこれを行うことはできますが、Perlのアレイスライス機能のおかげでPerlでは簡単です。 awkでは、同じ結果を得るために必要な配列を繰り返す必要があります。
#!/usr/bin/perl
use strict;
my @wanted; # array to hold the indices we want to print
while(<>) {
chomp;
# split the input line into array @F, using commas as the delimiter.
my @F = split /,/;
if ($. == 1) { # process the first line (the headers)
# if a header matches the regex, add it to @wanted
foreach my $i (0 .. $#F) {
push @wanted, $i if $F[$i] =~ m/^abc/i;
};
};
# print the columns of @F whose indices are listed in @wanted
print join(",", @F[@wanted]), "\n";
}
たとえば、別の名前で保存しabc.pl
て実行可能にしchmod +x abc.pl
たら、次のように実行します。
$ ./abc.pl input.csv
ABC1,ABC2,ABC3
1,2,3
1,2,3
動作原理:
- ループは、各フィールドの
foreach
一致するインデックス番号(大文字と小文字を区別しない)を配列に追加します。/abc/
@wanted
- 与えられたサンプル入力の後には、最終的に、とが
@wanted
含まれます。0
1
2
@F[@wanted]
ステートメントで使用されるasは実際にはprint join()
(つまり、要素とof)と同じです。これらの要素はコンマ文字で連結して印刷されます。@F[0,1,2]
0
1
2
@F
追加:
if ($. == 1) {...}
foreach
Perlの機能を使用するためにusingブロックを書き換えることができますgrep
。ブロック全体を1行に置き換えることができます。
@wanted = grep($F[$_] =~ m/^abc/i, keys @F) if ($. == 1);
一部の人々はこれがPerl寛容であると言うでしょう。私は同意しません。 Perlにはforeach
and grep
(およびmap
配列join
やリストを扱う他の多くの関数と演算子)があり、次のものを使用します。どのその中には「慣用的なパール」があります。
注:keys
インデックス配列を使用するには、2010年にリリースされたv5.12以降のPerlバージョンが必要です。以前はkeys
ハッシュ配列だけで作業していました。
さらに、スクリプト全体は、次の2つのステートメントのみを使用して1行に圧縮できます。
$ perl -F, -lne '@wanted = grep($F[$_] =~ m/^abc/i, keys @F) if ($. == 1);
print join(",", @F[@wanted]);' input.csv
答え3
答え4
flds=$(< file head -n 1 | tr ',' '\n' | grep -ne '^ABC' | cut -d: -f1 | paste -sd, -)
cut -d, -f"${flds}" file
ABC1,ABC2,ABC3
1,2,3
1,2,3
これを2つのステップで行います。まず、ヘッダーを抽出してから、ヘッダーからABCで始まるフィールドのフィールド番号を取得します。
次に、この情報を使用してcutコマンドに接続し、ファイル全体からこれらのフィールドを抽出します。