次のフィールドを含む非常に大きなCSVログファイルがあります。
aaa=somedata1,bbb=somedata2,ccc=somedata3,eee=somedata5,hhh=somedata8
aaa=somedata1,ddd=somedata4,fff=somedata6,hhh=somedata8
aaa=somedata1,bbb=somedata2,hhh=somedata8,ggg=somedata9,jjj=somedata11
このファイルの問題は、値が存在しないときに生成デバイスに "fieldname ="が含まれていないため、フィールドが欠落しているためCSVがソートされていないように見えることです(したがって、フィールドが欠落するたびに残りは削除されます)。現在のフィールドはCSVの左側にドラッグされます。
私の考えは、AWKを使用して特定の関連列のみを抽出し、それを新しいCSVに出力する必要があるということです。
たとえば、上記の例では、「aaa」フィールドと「hhh」フィールドを含むすべての列を抽出して、新しいCSVが次のように見えるようにします。
aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8
しかし、2つの質問があります。
- AWKで複数の条件を見つける方法がわかりません。必須フィールド/キーワードの名前をTXTファイルに書き込んでAWKから読み取ろうとしましたが、できませんでした。
- 結果の列を印刷しようとするたびに、新しいCSVは1つの大きな列だけを印刷し、列を分離して印刷する方法が見つからないようです。
どんな助けをありがとう!
---編集 1---
はい、次のような別々のAWKコマンドを試しました。
awk '{for (i=1;i<=NF;i++) if ($i ~ /aaa/) { print $i}}' > aaa.csv
awk '{for (i=1;i<=NF;i++) if ($i ~ /hhh/) { print $i}}' > hhh.csv
次に、次のことを試してみてください(もちろん、抽出したい列は合計10個ですが、簡単に説明するために、例には2つだけ入れました)。
paste -d "," aaa.csv hhh.csv > Allcolumns.csv
---編集 2---
合計10個の関連列があり、それを新しいファイルに抽出したいと思います。ソースファイルはログなので、すべての行に表示される列が実際に必要な列であることを確認してください。元のファイルに表示されない場合は、最良の方法は最終ファイルに「aaa、hhh、、iii」などの内容を反映することです。
ベストアンサー1
tag2val[]
データにタグと値のペアがあるときはいつでも、マップを保持する配列を作成してから(以下)、タグ(名前またはキーとも呼ばれる)ごとにすべての値を参照できることをお勧めします。
すべてのUnixシステムのすべてのシェルでawkを使用してください。
$ cat tst.awk
BEGIN {
FS = OFS = ","
numTags = split("aaa,hhh",tags)
}
{
delete tag2val
for (i=1; i<=NF; i++) {
tag = $i
sub(/=.*/,"",tag)
tag2val[tag] = $i
}
for (i=1; i<=numTags; i++) {
tag = tags[i]
printf "%s%s", tag2val[tag], (i<numTags ? OFS : ORS)
}
}
$ awk -f tst.awk file
aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8
各行ですべての可能なフィールドを印刷したい場合は、最初のパスで各行のすべての可能なフィールドを識別する2段階のアプローチです。
$ cat tst.awk
BEGIN {
FS = OFS = ","
}
NR==FNR {
for (i=1; i<=NF; i++) {
tag = $i
sub(/=.*/,"",tag)
if ( !seen[tag]++ ) {
tags[++numTags] = tag
}
}
next
}
{
delete tag2val
for (i=1; i<=NF; i++) {
tag = $i
sub(/=.*/,"",tag)
tag2val[tag] = $i
}
for (i=1; i<=numTags; i++) {
tag = tags[i]
printf "%s%s", tag2val[tag], (i<numTags ? OFS : ORS)
}
}
$ awk -f tst.awk file file
aaa=somedata1,bbb=somedata2,ccc=somedata3,eee=somedata5,hhh=somedata8,,,,
aaa=somedata1,,,,hhh=somedata8,ddd=somedata4,fff=somedata6,,
aaa=somedata1,bbb=somedata2,,,hhh=somedata8,,,ggg=somedata9,jjj=somedata11
すべての行に表示されるフィールドのみを印刷したい場合:
$ cat tst.awk
BEGIN {
FS = OFS = ","
}
NR==FNR {
for (i=1; i<=NF; i++) {
tag = $i
sub(/=.*/,"",tag)
cnt[tag]++
}
next
}
FNR==1 {
for (tag in cnt) {
if ( cnt[tag] == (NR-1) ) {
tags[++numTags] = tag
}
}
}
{
delete tag2val
for (i=1; i<=NF; i++) {
tag = $i
sub(/=.*/,"",tag)
tag2val[tag] = $i
}
for (i=1; i<=numTags; i++) {
tag = tags[i]
printf "%s%s", tag2val[tag], (i<numTags ? OFS : ORS)
}
}
$ awk -f tst.awk file file
hhh=somedata8,aaa=somedata1
hhh=somedata8,aaa=somedata1
hhh=somedata8,aaa=somedata1
フィールド出力の順序が重要な場合、これは簡単な調整でもあります。たとえば、入力順序を維持するには、次のように最初のブロックに配列を作成し、増分カウントを各新しいラベルにマップします。
$ cat tst.awk
BEGIN {
FS = OFS = ","
}
NR==FNR {
for (i=1; i<=NF; i++) {
tag = $i
sub(/=.*/,"",tag)
if ( !cnt[tag]++ ) {
order[++totTags] = tag
}
}
next
}
FNR==1 {
for (i=1; i<=totTags; i++) {
tag = order[i]
if ( cnt[tag] == (NR-1) ) {
tags[++numTags] = tag
}
}
}
{
delete tag2val
for (i=1; i<=NF; i++) {
tag = $i
sub(/=.*/,"",tag)
tag2val[tag] = $i
}
for (i=1; i<=numTags; i++) {
tag = tags[i]
printf "%s%s", tag2val[tag], (i<numTags ? OFS : ORS)
}
}
$ awk -f tst.awk file file
aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8