다수의 행에 대한 조회, 해시 및 교체 동시성

다수의 행에 대한 조회, 해시 및 교체 동시성

여러 개의 파일이 있고 각 줄에는 해시를 사용하여 마스크하려는 고유한 값이 있습니다.

그런데 파일에 300만 행이 있는데, 그 과정을 완료하는 데 걸리는 시간을 대략 계산하면 32일이라는 아주 긴 시간이다.

for y in files*; do 
  cat $y | while read z; do
    KEY=$(echo $z | awk '{ print $1 }' | tr -d '"')
    HASH=$(echo $KEY | sha1sum | awk '{ print $1 }')
    sed -i -e "s/$KEY/$HASH/g" $y
  done
done

이 프로세스의 속도를 높이려면 동시성을 도입해야 한다고 생각합니다.

성급한 시도를 바탕으로https://unix.stackexchange.com/a/216475나를 데려가다

N=4
(
for y in gta*; do 
  cat $y | while read z; do
    (i=i%N)); ((i++==0)); wait
    ((GTA=$(echo $z | awk '{ print $1 }' | tr -d '"')
    HASH=$(echo $GTA | sha1sum | awk '{ print $1 }')
    sed -i -e "s/$KEY/$HASH/g) & 
  done
done
)

그 성능은 더 나을 수 없습니다.

입력 예

"2000000000" : ["200000", "2000000000"]
"2000000001" : ["200000", "2000000001"]

출력 예

"e8bb6adbb44a2f4c795da6986c8f008d05938fac" : ["200000", "e8bb6adbb44a2f4c795da6986c8f008d05938fac"]
"aaac41fe0491d5855591b849453a58c206d424df" : ["200000", "aaac41fe0491d5855591b849453a58c206d424df"]

어쩌면 동시에 줄을 읽은 다음 각 줄에서 해시 교체를 수행해야 할까요?

답변1

FWIW 나는 이것이 쉘 스크립트에서 이 작업을 수행하는 가장 빠른 방법이라고 생각합니다.

$ cat tst.sh
#!/usr/bin/env bash

for file in "$@"; do
    while IFS='"' read -ra a; do
        sha=$(printf '%s' "${a[1]}" | sha1sum)
        sha="${sha% *}"
        printf '%s"%s"%s"%s"%s"%s"%s"\n' "${a[0]}" "$sha" "${a[2]}" "${a[3]}" "${a[4]}" "$sha" "${a[6]}"
    done < "$file"
done

$ ./tst.sh file

$ cat file
"e8bb6adbb44a2f4c795da6986c8f008d05938fac" : ["200000", "e8bb6adbb44a2f4c795da6986c8f008d05938fac"]"
"aaac41fe0491d5855591b849453a58c206d424df" : ["200000", "aaac41fe0491d5855591b849453a58c206d424df"]"

하지만 제가 댓글에서 언급한 것처럼 실행 속도를 향상하려면 sha1sum 기능이 내장된 도구(예: Python)를 사용하는 것이 더 좋습니다.

답변2

Python의 도움으로 Ed Morton의 제안을 따릅니다.

Python 스크립트 /tmp/sha1.py를 생성하고 실행 가능하게 만듭니다.

#! /usr/local/bin/python -u

import hashlib
import sys

for line in sys.stdin:
  words = line.split()
  str_hash=hashlib.sha1(words[0].encode())
  words[0] = str_hash.hexdigest()
  print(" ".join(words))

첫 번째 줄에는 Python의 올바른 위치가 포함되어야 하지만 "-u"는 제거하지 마세요.

그런 다음 실행 가능하게 만들어야 하는 ksh 스크립트가 있습니다.

#! /usr/bin/ksh

/tmp/sha1.py |&

for y in files*
do
  while read A B
  do
    eval "echo $A" >&p
    read A <&p
    echo \"$A\" $B
  done < $y > TMP.$y
  mv TMP.$y $y
done

# terminate sha1.py
exec 3>&p
exec 3>&-

이제 성능을 원한다면 Python이 한 번에 하나의 완전한 파일을 처리하도록 해야 합니다. 다음 스크립트는 각 입력 줄을 파일 이름으로 처리하고 더러운 작업을 수행합니다.

#! /usr/local/bin/python

import hashlib
import os
import sys

for IFileNmX in sys.stdin:
  IFileNm = IFileNmX.strip()
  IFile = open(IFileNm,'r')
  OFileNm = ".".join(["TMP",IFileNm])
  OFile = open(OFileNm,'w')
  for line in IFile.readlines():
    words = line.split()
    word1 = words[0].strip('"')
    str_hash=hashlib.sha1(word1.encode())
    words[0] = "".join(['"',str_hash.hexdigest(),'"'])
    OFile.write("".join([" ".join(words),'\n']))
  OFile.close()
  IFile.close()
  os.rename(OFileNm,IFileNm)

이 스크립트 /tmp/sha1f.py를 호출하여 실행 가능하게 만들면 몇 분 정도 걸리는지 알고 싶습니다.

ls files* | /tmp/sha1f.py

빼앗길 것이다. 내 시스템은 400Mb, 100만 줄의 파일을 처리하는 데 12초가 걸렸습니다. 그러나 이것은 물론 자랑이다.

관련 정보