Bash脚本csv操作优化

时间:2017-01-04 14:21:21

标签: bash csv

我有200万行csv文件,其中我要做的是用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

4 个答案:

答案 0 :(得分:1)

你可以在几行中轻松地在Perl中完成这项工作。以下程序使用Crypt::Digest::SHA256,您需要从CPAN或您的操作系统存储库安装它。

程序假定来自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

答案 1 :(得分: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()

仍然有一些点可以优化,但中心点可以基于do try而不是check,并且在重复用户不必重新删除用户名的情况下保存用户哈希值。 / p>

另外,您是否会在多核主机上运行它?..使用线程可以很容易地改进它。

答案 2 :(得分: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)

答案 3 :(得分:0)

由于您在原始尝试中使用了awk,因此awk

中的方法更为简单
awk -F"," 'BEGIN{i=0;}
           {if (unique_names[$2] == "") {
                unique_names[$2]="Unique"i;
                i++;
            }
            $2=unique_names[$2];
            print $0}'