awkを使用して新しい行を印刷する

awkを使用して新しい行を印刷する

ファイル数が多く、特定の行をインポートしてから、インポートしたデータをスプレッドシートに入れる必要があります。私のファイルに表示される内容は次のとおりです。

Name: w

Age: x

Height: y

Weight: z

年齢、身長、体重だけが欲しいので、まず以下を実行します。

grep -E 'Age|Height|Weight' [input file] > output.txt

ファイル数が多いので、出力は次のようになります。

Age 1
 
Height 1

Weight 1

Age 2

Height 2

Weight 2

etc...

今私が望むのは、awkスクリプトを実行して新しいoutput.txtファイルを通過し、最初に「Age」という単語を含む各行を見つけて印刷することです。すべての「年齢」計算が完了すると、身長と体重が計算されます。私はスクリプトを実行しました:

awk -F"\t" '/Age/ {print} /Height/ {print}' output.txt >output2.txt

ただし、元の出力ファイルのように印刷するだけです。すべての年齢が完了したら、キーを見つけるようにどのように変更しますか?

編集する:

私が望む出力はファイルです

1歳

2歳

高さ1

高さ2

重量1

重量2

など..

明確にするために、age1は「age」などを含むfile1の行です。

答え1

awkはデフォルトでファイルを一度だけ実行し、すべてのブロックを順番に実行するので、出力が提供されます。以下を使用して目的の動作を取得できます。ソートファイルを一度だけ処理しながら、いつでも行を保存します。

BEGIN {
    AgeIndex = 1
    HeightIndex = 1
}
/Age/ {
    ages[AgeIndex] = $0
    AgeIndex+=1
}
/Height/ {
    heights[HeightIndex] = $0
    HeightIndex+=1
}
END {
    for (x = 1; x < AgeIndex; x++)
        print ages[x] "\n"
    for (x = 1; x < HeightIndex; x++)
        print heights[x] "\n"
}

保存しfilter.awkたら、次を実行します。

awk -f filter.awk output.txt > output2.txt

希望の出力を取得します。

$ awk -f filter.awk < data
Age 1

Age 2

Height 1

Height 2

私たちがやっていることは、2つの配列を作成し、一致するages各行heightsをその配列に格納することです。AgeIndex到達した距離を配列として保存します。最後に、保存した各行(必要な追加の改行を含む)を最初にすべての年齢、次にすべての高さで印刷します。

配列はファイル全体をメモリに保存するため、ファイルが特に大きい場合は、ファイル全体を複数回繰り返すのにかかる時間とメモリ使用量をトレードオフする必要があります。この時点では、本質的に他の言語と同じプログラムです。 awkを使用する特別な理由がなければ、他の言語を好むかもしれません。正直なところ、私は提案したいと思います - awkはここではあまり役に立ちません。

答え2

そしてgawk

$ awk -F"\t" '
    { a[$1]++ }
    END {
        n = asorti(a,b);
        for (i = 1; i <= n; i++) {
            print b[i];
            if (i%2 == 0) {
                printf "\n";
            }
        }
    }
' output.txt
Age 1
Age 2

Height 1
Height 2

Weight 1
Weight 2

答え3

私は空の行が実際のファイルの一部であるとは思わないし、少なくとも気にしません。その場合、必要なものは次のとおりですsort

$ cat output.txt
Age 1
Height 1
Weight 1
Age 2
Height 2
Weight 2

$ sort output.txt
Age 1
Age 2
Height 1
Height 2
Weight 1
Weight 2

ただし、ファイルが大きすぎてメモリに保存できない場合を除き、作業全体を1つの手順で実行する方が簡単です。

grep -whE 'Age|Height|Weight' *txt | sort > outfile

上記のコマンドは、現在のディレクトリ()内のAge名前または末尾のすべてのファイルを検索します。 「完全な単語のみ一致」(つまり一致しない)を意味します。これがないと、複数の入力ファイルが指定されたときにファイル名が一致する行と一緒に印刷されるために必要です。拡張正規表現を使用してORを提供します。HeightWeighttxt*txt-wAgeAgeing-h-E|

メモ: 何らかの理由で各項目の間に空白行を追加したい場合(コマンドで生成されるものではないgrep)、次のように追加できます。

grep -whE 'Age|Height|Weight' *txt | sort | sed 's/$/\n/'

はい

$ for i in {1..3}; do echo -e "Name $i\nAge $i\nHeight $i\nWeight $i" > $i.txt; done
$ for f in *txt; do echo " -- $f --"; cat $f; done
 -- 1.txt --
Name 1
Age 1
Height 1
Weight 1
 -- 2.txt --
Name 2
Age 2
Height 2
Weight 2
 -- 3.txt --
Name 3
Age 3
Height 3
Weight 3

$ grep -whE 'Age|Height|Weight' *txt | sort
Age 1
Age 2
Age 3
Height 1
Height 2
Height 3
Weight 1
Weight 2
Weight 3

とにかく、sortそれがあなたに適していなくても、代わりにPerlで次のようなことをしますawk(これはあなたが追加の空行を望んでいると仮定しますが、おそらくあなたはそうではありません):

$ perl -ane '$k{$F[0]}.=$_."\n" if /./; 
    END{print $k{$_},"\n" for sort keys (%k)}' output.txt 
Age 1

Age 2


Height 1

Height 2


Weight 1

Weight 2


 

必要でない場合は、head -n -2最後の2つの空行を削除するために使用できます。

答え4

pythonこの問題に対する解決策:

from collections import defaultdict
f = open("output.txt", "r")
d = defaultdict(list)
for line in f:
   line = line.strip()
   if line != '':
     arr = line.split(" ")
     d[arr[0]].append(arr[1])
print d.items()

最初の列を使用してハッシュしてリストに入れました。

関連情報