3

2つの表形式のファイルがあります。1つのファイルには、 lookup_file.txtと呼ばれる50個のキー値のマッピングが含まれています。 もう1つのファイルには、30列と数百万行の実際の表形式のデータが含まれています。data.txt2番目のファイルのid列をlookup_file.txt の値に置き換えたいと思います。。

これどうやってするの?bashスクリプトでawkを使用したいです。また、別のファイルではなく、50個のキー/値を格納するためにbashで使用できるハッシュマップデータ構造はありますか?

4

4 に答える 4

7

ファイルにコンマ区切りのフィールドがあり、「id列」がフィールド3であると仮定します。

awk '
BEGIN{ FS=OFS="," }
NR==FNR { map[$1] = $2; next }
{ $3 = map[$3]; print }
' lookup_file.txt data.txt

これらの仮定のいずれかが間違っている場合、修正が明らかでない場合は私たちに手がかりを与えてください...

編集:そして(IMHO無視できる)NR == FNRテストのパフォーマンスへの影響を避けたい場合、これはgetl​​ineの使用が適切である場合のすべてのまれなケースの1つです:

awk '
BEGIN{
   FS=OFS=","
   while ( (getline line < "lookup_file.txt") > 0 ) {
      split(line,f)
      map[f[1]] = f[2]
   }
}
{ $3 = map[$3]; print }
' data.txt
于 2012-11-26T21:15:40.900 に答える
4

awk / sedで記述する代わりに、bashを介して「sort」と「join」を組み合わせて使用​​することができ、さらに高速になる可能性があります。

key.cvs(id、name)

1,homer
2,marge
3,bart
4,lisa
5,maggie

data.cvs(名前、動物、所有者、年齢)

snowball,dog,3,1
frosty,yeti,1,245
cujo,dog,5,4

ここで、最初に両方のファイルをユーザーID列で並べ替える必要があります。

cat key.cvs | sort -t, -k1,1 > sorted_keys.cvs
cat data.cvs | sort -t, -k3,3 > sorted_data.cvs

次に、2つのファイルを結合します。

join -1 1 -2 3 -o "2.1 2.2 1.2 2.4" -t , sorted_keys.cvs sorted_data.cvs > replaced_data.cvs

これにより、次のようになります。

snowball,dog,bart,1
frosty,yeti,homer,245
cujo,dog,maggie,4

これ:

-o "2.1 2.2 1.2 2.4"

最終出力に必要な2つのファイルの列を示しています。

他のスクリプト言語と比較して、データの複数のギグを見つけて置き換えるのはかなり高速です。私はSED/AWKと直接比較していませんが、SED / AWKで書くよりも、これをラップするbashスクリプトを書く方がはるかに簡単です(少なくとも私にとっては)。

また、gnu coreutilsのアップグレードバージョンを使用して並べ替えを高速化できるため、並べ替えを並行して実行できます

cat data.cvs | sort --parallel=4 -t, -k3,3 > sorted_data.cvs

4は、実行するスレッドの数です。通常、マシンコアごとに2つのスレッドがマシンを最大化することをお勧めしますが、これ専用の場合は問題ありません。

于 2012-11-28T08:35:37.883 に答える
1

これを行うにはいくつかの方法があります。しかし、検証の方法をあまり使わずに、簡単な1つのライナーが必要な場合は、awk/sedソリューションを使用します。

次のように想定します。

  1. ファイルはタブ区切りです

  2. bashシェルを使用しています

  3. データファイルのIDは最初の列にあります

  4. ファイルは次のようになります。

見上げる

1   one
2   two
3   three
4   four
5   five

データ

1   col2    col3    col4    col5
2   col2    col3    col4    col5
3   col2    col3    col4    col5
4   col2    col3    col4    col5
5   col2    col3    col4    col5

私はこのタスクを次のように使用awkして実行します。sed

awk '{print "sed -i s/^"$1"/"$2"/ data"}' lookup | bash

これが行っているのは、ルックアップの各行を調べて、stdoutに次のように書き込むことです。

sed -i s/^1/one/ data

sed -i s/^2/two/ data

等々。

次に、各行をシェル(| bash)にパイプ処理し、シェル()が式を実行しsedます。-iインプレースの場合-i.bak、バックアップファイルを作成することをお勧めします。拡張子は好きなように変更できることに注意してください。sedは、で示されているように、行の先頭でIDを探してい^ます。IDを含まない可能性のある列の「id」を置き換えたくない場合。

出力は次のようになります。

one     col2    col3    col4    col5
two     col2    col3    col4    col5
three   col2    col3    col4    col5
four    col2    col3    col4    col5
five    col2    col3    col4    col5

もちろん、IDはおそらく1対1、2対2などではありませんが、これにより正しい方向に進むことができます。そして、私はこの用語を非常に大まかに使用します。

于 2012-11-26T18:11:17.340 に答える
0

私がこれを行う方法は、より大きなファイルを処理awkするプログラムを作成するために使用することです。awk

awk -f <(awk '
   BEGIN{print " BEGIN{"}
        {printf "      a[\"%s\"]=\"%s\";",$1,$2}
   END  {print "      }";
         print "      {$1=a[$1];print $0}"}
   ' lookup_file.txt
) data.txt

idこれは、列が列1であることを前提としています。$1そうでない場合は、の両方のインスタンスを変更する必要があります$1=a[$1]

于 2012-11-26T18:07:29.700 に答える