- 출처 : 유닉스 리눅스 쉘스크립트 예제사전_한빛미디어
명령어: paste, md5sum, read, awk
키워드: 해시, 페이스트, 컬럼
사용처: 파일에서 입력값을 읽어서 줄마다 해시값을 계산해서 CSV 파일에 출력하고 싶을 때
실행예제
$ cat data.txt
abcdefg
password
123456
$ ./paste.sh data.txt
abcdefg,7ac66c0f148de9519b8bd264312c4d64
password,5f4dcc3b5aa765d61d8327deb882cf99
123456,e10adc3949ba59abbe56e057f20f883e
스크립트
#!/bin/sh
# 해시값을 출력할 임시 파일을 초기화
tmpfile="hash.txt" #-------------------------------------------- 1
: > $tmpfile #-------------------------------------------------- 1
# 셸 구분자를 줄바꿈만 인식하도록 변경
IFS='
' #------------------------------------------------------------- 2
# 지정한 텍스트 파일에서 한 줄씩 읽어들림
while read -r line #-------------------------------------------- 3
do
# MD5 해시 취득
# 명령어에 파일명이 따라오므로 첫 번째 컬럼만 추출
echo -n "$line" | md5sum | awk '{print $1}' >> $tmpfile #--- 5
done < $1 #----------------------------------------------------- 4
# 원본 텍스트 파일과 해시를 출력한 임시 파일을 쉼표로 연결해서 표시
paste -d, "$1" $tmpfile #--------------------------------------- 6
해설
이 스크립트는 지정한 텍스트 파일 각 줄마다 MD5 해시값을 계산해서 그 값을 컴마로 구분한 CSV 형식으로 출력합니다.
MD5는 해시 함수 중 하나로 입력된 값에서 128비트 해시값을 출력합니다. 해시값이란 메시지 다이제스트라고 부르며 입력값에 대해 해시 함수로 계산한 값입니다. 메시지가 깨졌는지 누군가가 몰래 고치지 않았는지 등을 간단히 확인할 수 있어 널리 사용됩니다.
-
한 글자만 달라도 해시값은 크게 달라짐
$ echo -n "ABCDEFGABCDEFGABCDEFGABCDEFGABCDEFG" | md5sum bd3b9bbc014d8f8ebc284d5d590bdb1a - $ echo -n "AACDEFGABCDEFGABCDEFGABCDEFGABCDEFG" | md5sum 70709a03675c0677ca0a1ce9aea53f75 -
MD5 해시값을 얻어 md5sum 명령어로 출력한 예입니다. 여기서 “ABCDEFG”가 5번 반복된 문자열 해시값을 우선 구한 다음, 두 번째 B를 A로 바꾼 문자열 해시값을 구합니다. echo 명령어에서 줄바꿈을 하지 않는 -n 옵션을 써서 문자열로만 해시값을 구합니다. 한 글자만 바뀌었지만 출력된 해시값은 크게 다릅니다. 이렇듯 해시값을 비교하면 메시지가 변경되었는지 깨지지 않았는지 판정할 수 있습니다. 하지만 출력된 해시값에서 역으로 원래 입력값을 구하는 것은 어렵습니다.
예제 스크립트는 우선 입력 파일 각 줄을 읽어서 해시값을 계산하여 다른 파일에 출력합니다. 따라서 임시 파일의 초기화를 1
에서 수행합니다.
2
는 IFS에 줄바꿈을 대입해서 셸 구분자로 줄바꿈만 설정합니다. 셸은 스페이스 기호를 기본 구분자로 사용하므로 그냥 사용하면 스크립트에서 파일을 읽을 때 단어 앞머리 등에 스페이스가 있다면 구분자로 인식해서 제대로 된 해시값을 얻지 못합니다. 따라서 구분자를 미리 변경해둡니다.
IFS 설정방법은 아래 링크에서 설명했으니 참조하기 바랍니다.
IFS 참고:
https://blessu1201.github.io/2024/02/05/linux-file-ls-case-048.html
3
에서는 while문을 사용해 read 명령어로 지정한 입력 파일에서 한 줄씩을 셸 변수 line에 읽어들입니다. 4
에서 while문 전체에 입력 리다이렉트하므로 명령행 인수로 지정한 파일에서 읽기 처리를 합니다. 그리고 3
의 read 명령어에서 백슬래시()가 있는 문자를 그대로 다룰 수 있도록 -r 옵션을 사용합니다. -r 옵션이 없으면 “abcd\nefgh”라는 문자열에 있는 \n 을 줄바꿈 문자로 인식하게 됩니다. 5
는 해시값을 계산한 처리 부분입니다. md5sum 명령어에 파이프로 연결한 echo 명령어를 사용해 값을 입력합니다. md5sum 명령어 출력에는 파일명이 따라오므로(예제에서는 표준 입력이므로) awk 명령어로 첫 번째 컬럼값만 추출합니다. 그 결과를 임시 파일 $tmpfile에 출력합니다.
그 결과 임시 파일 $tmpfile 내용은 다음과 같은 해시값의 나열입니다.
7ac66c0f148de9519b8bd264312c4d64
5f4dcc3b5aa765d61d8327deb882cf99
e10adc3949ba59abbe56e057f20f883e
마지막으로 6
에서 원래 파일 data.txt와 해시값을 기록한 임시 파일 $tmpfile을 연결합니다. paste 명령어를 사용하는데 두 텍스트 파일을 횡방향으로 연결하는 명령어입니다. 기본값은 탭 구분자를 사용하므로 여기에서는 CSV 파일이 되도록 쉼표를 -d 옵션으로 지정합니다(“-d,” 처럼 작성합니다). 이렇게 하면 원래 값과 해시값을 CSV 파일로 생성할 수 있습니다.
해시값을 다른 스크립에서 재이용하고 싶으면 일단 별도의 파일(hash.txt)에 출력해두면 됩니다.
주의사항
- FreeBSD나 Mac에서는 md5sum이 아닌 md5 명령어를 사용합니다.
echo $line | md5 | awk '{print $1}' >> $tmpfile
- MD5는 해시값으로 128비트를 사용하므로 현재는 안전성이 높은 SHA 형식을 더 많이 사용합니다. 하지만 SHA 형식을 다루는 명령어는 OS에 따라 기본 설치되지 않을 수도 있으므로 여기에서는 MD5를 사용했습니다.