2017-01-04 23 views
0

私は、csvファイルの各行の2番目の列をその文字列の一意の値に置き換える200万行のcsvファイルを用意しています。これらはすべてユーザー名で埋められています。私が下にある長いプロセスはうまくいくが、しばらく時間がかかる。Bashスクリプトのcsv操作の最適化

これはハッシュする必要はありませんが、これは次のファイルが矛盾しない場合の確実な方法のようです。

私は決してコーダーではなく、とにかくプロセスを最適化できるかどうか疑問に思っていました。これを行う最善の方法を理解していますが、何らかのスクリプト言語で書かれています。

#!/bin/bash 
#Enter Filename to Read 
echo "Enter File Name" 
read filename 
#Extracts Usersnames from file 
awk -F "\"*,\"*" '{print $2}' $filename > usernames.txt 
#Hashes Usernames using SHA256  
cat usernames.txt | while read line; do echo -n $line|openssl sha256 |sed  's/^.* //'; done > hashedusernames.txt 
#Deletes usernames out of first file 
cat hash.csv | cut -d, -f2 --complement > output.txt 
#Pastes hashed usernames to end of first file 
paste -d , output.txt hashedusernames.txt > output2.txt 
#Moves everything back into place 
awk -F "\"*,\"*" '{print $1","$4","$2","$3}' output2.txt > final.csv 

サンプルファイルは、全部で7列があるだけ3は

Time Username Size 
2017-01-01T14:53.45,Poke.callum,12345 
2016-01-01T13:42.56,Test.User,54312 
2015-01-01T12:34.34,Another.User,54123 
+0

ユーザー名の別のリストを取得し、それらを別々にハッシュしてから参加することを検討しましたか?はい、データベースやスクリプト言語がおそらくそれに適しています。 –

+0

これは繰り返し発生する問題ですか?あなたはいつも同じファイルサイズでそれを行う必要がありますか? – simbabque

+0

これは毎日、はるかに小さいファイルで行うことができます。それはすべてELKスタックにフィードされますが、それでもこのサイズのファイルで使用する必要があります。 – Pokecallum

答えて

1

あなたは数行で簡単にPerlでこれを行うことができます。以下のプログラムはCrypt::Digest::SHA256を使用しています.CPANまたはOSリポジトリからインストールする必要があります。

このプログラムでは、DATAセクションからの入力を想定しています。このセクションは、通常、mcveにサンプルデータを含めるためにここで行います。

use strict; 
use warnings; 
use Crypt::Digest::SHA256 'sha256_b64u'; 

while (my $line = <DATA>) { 
    # no need to chomp because we don't touch the last line 
    my @fields = split /,/, $line; 
    $fields[1] = sha256_b64u($fields[1]); 
    print join ',', @fields; 
} 

__DATA__ 
2017-01-01T14:53.45,Poke.callum,12345 
2016-01-01T13:42.56,Test.User,54312 
2015-01-01T12:34.34,Another.User,54123 

以下の出力を出力します。

2017-01-01T14:53.45,g8EPHWc3L1ln_lfRhq8elyOUgsiJm6BtTtb_GVt945s,12345 
2016-01-01T13:42.56,jwXsws2dJq9h_R08zgSIPhufQHr8Au8_RmniTQbEKY4,54312 
2015-01-01T12:34.34,mkrKXbM1ZiPiXSSnWYNo13CUyzMF5cdP2SxHGyO7rgQ,54123 

それは、コマンドライン引数として指定されたファイルを読み込む作成し、.new拡張子を持つ新しいファイルに書き込む、あなたはこのようにそれを使用することができますするには、次のように

use strict; 
use warnings; 
use Crypt::Digest::SHA256 'sha256_b64u'; 

open my $fh_in, '<', $ARGV[0] or die $!; 
open my $fh_out, '>', "$ARGV[0].new" or die $!; 

while (my $line = <$fh_in>) { 
    # no need to chomp because we don't touch the last line 
    my @fields = split /,/, $line; 
    $fields[1] = sha256_b64u($fields[1]); 
    print $fh_out join ',', @fields; 
} 

はそれを実行します:

$ perlのfoo.pl example.csv

新しいファイルがexample.csv.newという名前になります。

+0

ありがとう、私はこれが完全に動作すると思います。perlモジュールの動作を得るためにすべてのインストーラを見つけることができるときにテストを行ってください。 – Pokecallum

0

このPythonプログラムは、あなたがやりたいことがあります表示されます。あなたは、コマンドラインで変換するには、ファイル名を渡すことができます。

$ python this_program.py file1.csv file2.csv 

 

import fileinput 
import csv 
import sys 
import hashlib 


class stdout: 
    def write(self, *args): 
     sys.stdout.write(*args) 

input = fileinput.input(inplace=True, backup=".bak", mode='rb') 
reader = csv.reader(input) 
writer = csv.writer(stdout()) 

for row in reader: 
    row[1] = hashlib.sha256(row[1]).hexdigest() 
    writer.writerow(row) 
0

、あなたのオリジナルの試みでawkを使用しているので、ここではawk

awk -F"," 'BEGIN{i=0;} 
      {if (unique_names[$2] == "") { 
       unique_names[$2]="Unique"i; 
       i++; 
      } 
      $2=unique_names[$2]; 
      print $0}' 
1

で簡単な方法は、速度だけでなく、メンテナンス性に焦点を当て、さらに別のPythonのソリューションです。

#!/usr/bin/python3 

import argparse 
import hashlib 
import re 

parser = argparse.ArgumentParser(description='CSV swaper') 
parser.add_argument(
    '-f', 
    '--file', 
    dest='file_path', 
    type=str, 
    required=True, 
    help='The CSV file path.') 

def hash_user(users, user): 
    try: 
     return users[user] 
    except KeyError: 
     id_ = int(hashlib.md5(user.encode('utf-8')).hexdigest(), 16) 
     users[user] = id_ 
     return id_ 
def main(): 
    args = parser.parse_args() 
    username_extractor = re.compile(r',([\s\S]*?),') 
    users = {} 
    counter = 0 
    templ = ',{},' 
    with open(args.file_path) as file: 
     with open('output.csv', 'w') as output: 
      line = file.readline() 
      while line: 
       try: 
        counter += 1 
        if counter == 1: 
         continue 
        username = username_extractor.search(line).groups()[0] 
        hashuser = hash_user(users, username) 
        output.write(username_extractor.sub(
         templ.format(hashuser), line) 
        ) 
       except StopIteration: 
        break 
       except: 
        print('Malformed line at {}'.format(counter)) 
       finally: 
        line = file.readline() 

if __name__ == '__main__': 
    main() 

があり、まだ最適化することができ、いくつかのポイントですが、中央のものではなく、チェックのtryを行うに基づいており、そこに繰り返され、ユーザーはユーザー名をredigestする必要はありません場合には、ユーザーのハッシュを保存します。

また、これをマルチコアホスト上で実行しますか?これはスレッドを使用して簡単に改善することができます。

+0

Unfortunatlyこれは2番目の列だけでなく2番目の列をハッシュします。 – Pokecallum

+0

マルチコアマシン – Pokecallum

+0

私は第2列についてのコメントを理解していませんでした。詳細を教えてください。コアロジックが正常になったら、このスクリプトをマルチコア電源を使用するように変えることができます。 –

関連する問題