제어 구문 예제_06 웹 서버에서 파일을 내려받아서 MD5 해시값 계산하기

 
  • 출처 : 유닉스 리눅스 쉘스크립트 예제사전_한빛미디어

명령어: curl, md5sum
키워드: 내려받기, 종료 스테이터스
사용처: 네트워크 경유로 파일을 취득할 때 복사에 성공했는지 확인해서 다음 명령어를 실행하고 싶을 때


실행예제

$ ./andlist.sh
83036ec1109bf9770fc2d8673b545d35 sample.dat

스크립트

#!/bin/sh

# 내려받을 파일 URL 경로, 파일명 지정
url_path="http://www.example.org/"  #------------------------ 1
filename="sample.dat"  #------------------------------------- 1

# 파일 내려받기. 내려받기에 성공하면 md5 해시값 표시
# Mac/FreeBSD라면 md5sum 명령어가 아니라 md5 명령어 사용
curl -sO "${url_path}${filename}" && md5sum "$filename"  #--- 2

# 내려받기 파일을 삭제하고 종료
rm -f "$filename"  #----------------------------------------- 3

   

해설

이 스크립트는 셸 변수 url_path와 filename으로 지정한 웹 페이지에서 파일을 내려받아서 MD5 해시값을 표시합니다. 매일 바뀌는 내용을 정기적으로 확인하는 용도로 사용한다고 가정합니다.MD5 해시값은 텍스트처리_04 입력 파일 해시값을 줄마다 추가해서 출력하기 을 참조하기 바랍니다.

외부 파일을 내려받을 때 네트워크 문제로 실패할 수도 있다는 걸 고려해야 합니다. 예제에서는 내려받기에 실패하면 md5 명령어를 실행하지 않도록 해서 잘못된 값을 출력하지 않습니다. 따라서 2에서 AND 연산자(&&)를 사용합니다.

AND 연산자(&&)는 좌우에 두 명령어를 작성해서 a && b 형태로 사용합니다. “a와 b가 둘 다 참이라면 참”이란 의미입니다. 하지만 실행 예에서는 ‘좌측 명령어 a가 성공(종료 스테이터스가 0)일 때만 우측 명령어 b를 실행한다’는 뜻으로 사용하는 것이 일반적입니다. 이것을 a && b라고 쓰면 만약 좌측이 거짓이면 전체 평가식은 거짓이 되므로 우측을 실행할 필요가 없어서, 결과적으로 좌측 명령어 종료 시점에 끝나기 때문입니다.

즉, AND 연산자는 단순히 ‘앞 명령어가 성공하면 다음 명령어를 실행한다’고 생각하면 쉽습니다. AND 연산자의 이런 성격은 셸 스크립트뿐만 아니라 자바나 펄 같은 다른 프로그램밍 언어에서도 자주 사용하므로 기억해두기 바랍니다.

예제에서 1은 내려받을 파일과 URL을 정의합니다. 여기서 다음 처리를 사용하기 쉽도록 URL 경로(url_path)와 파일명(filename)을 각각 변수로 정의합니다.

2에서 curl 명령어로 파일을 내려받습니다. curl 명령어에 중간 상황을 표시하지 않는 -s 옵션(silent 모드)과 내려받은 파일을 표준 출력이 아니라 파일로 저장하는 -O 옵션을 사용합니다.

2는 AND 연산자로 curl 명령어와 md5sum 명령어를 연결합니다. 만약 네트워크 이상으로 curl 명령어가 실패하면 curl 명령어 종료 스테이터스로 0이 아닌 값이 돌아옵니다. 즉, curl 명령어에 실패하면 우측 md5 명령어는 실행되지 않습니다. 이렇게 해서 내려받기에 실패했을 때 MD5 해시값을 계산하는 오작동을 방지할 수 있습니다.

내려받은 파일이 남아 있으므로 3에서 삭제합니다. rm 명령어는 -f 옵션을 써서 만약 내려받기에 실패해서 파일이 없을 때도 에러가 발생하지 않도록 합니다.

   

AND 연산자 세부 내용

AND 연산자 사용 예를 좀 더 살펴봅시다. 그외의 &&가 자주 사용되는 것은 현재 디렉터리를 이동하는 cd 명령어와 세트로 사용하는 경우입니다.

cd "$appdir" && ./script.sh

셸 스크립트는 원래라면 어떤 경로에 있더라도 동작하도록 작성하는 것이 좋습니다. 하지만 실제로는 디렉터리를 cd 명령어로 이동해서 실행하지 않으면 정상적으로 동작하지 않는 경우도 많습니다. 따라서 처음에 cd로 스크립트가 있는 디렉터리로 이동하는 경우도 많습니다.

앞에서는 cd 명령어와 ./script.sh라는 실행 명령을 AND 연산자(&&)로 연결합니다. 이러면 디렉터리명을 실수했거나 해서 cd 명령어에 실패하면 ./script.sh가 실행되지 않습니다. 만약 AND 명령어 없이 다음처럼 작성하면 cd 이동에 실패했더라도 만약 같은 이름의 script.sh라는 파일이 현재 디렉터리에 있으면 실행됩니다.

cd "$appdir"
./script.sh

이렇듯 가능하면 에러 발생을 고려해서 작성하는 것이 좋습니다.

   

주의사항

  • curl 명령어는 뭐든 결과를 전송받기만 하면 HTTP 스테이터스 결과를 무시합니다. 즉, 404 Not Found 페이지의 에러 구문이라도 해당 페이지의 내용을 전송받는다면 종료 스테이터스가 0이더라도 다음 처리로 넘어갑니다.

  • AND 연산자와 대비되는 것이 OR 연산자(||)입니다. a || b는 ‘a 또는 b가 참이면 참’을 의미합니다. 하지만 실제로는 ‘좌측 명령어 a가 실패(종료 스테이터스가 0 이외)일 때만 우측 명령어 b를 실행’ 하도록 사용하는 것이 일반적입니다. 예를 들어 다음은 셸 변수 filename으로 지정한 파일이 존재하는지 test 명령어로 확인합니다. 파일이 없으면 exit 명령어를 실행해서 스크립트를 종료합니다.

test -f "$filename" || exit 1