2017-01-04 1 views
0

나는 CSV 파일의 각 행의 두 번째 열을 해당 문자열에 대한 고유 한 값으로 바꾸는 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

당신은 몇 줄에 쉽게 펄에서이 작업을 수행 할 수있다. 다음 프로그램은 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; 
} 

실행은 다음과 같이 :

$ 펄 foo.pl example.csv 새 파일이 example.csv.new을 지정됩니다

.

당신이 원래 시도 awk을 사용하기 때문에
+0

감사합니다, 이것이 완벽하게 작동 할 것이라고 상상해보십시오. 모든 설치자가 펄 모듈을 작동 시키도록 모든 설치자를 찾을 수있을 때 테스트 해주세요. – Pokecallum

0

이 파이썬 프로그램은 당신이 원하는 것을 할 수있는 표시됩니다. 명령 줄에서 변환 할 파일 이름을 전달할 수 있습니다

$ 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 -F"," 'BEGIN{i=0;} 
      {if (unique_names[$2] == "") { 
       unique_names[$2]="Unique"i; 
       i++; 
      } 
      $2=unique_names[$2]; 
      print $0}' 
1

또 다른 파이썬 솔루션의 단순한 접근 방식, 속도에 초점을뿐만 아니라 유지 보수에.

#!/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이 코드는 두 번째 열뿐만 아니라 두 번째 열 모두를 해시합니다. – Pokecallum

+0

멀티 코어 머신에있을 것입니다 – Pokecallum

+0

두 번째 열에 대한 의견을 이해할 수 없었습니다. 자세히 설명해 주시겠습니까? 그리고 코어 로직이 괜찮다면 멀티 코어 파워를 사용하도록이 스크립트를 변형 할 수 있습니다. –