[Linux 셸 스크립트] 변환처리 - 018 HTML 파일에서 태그 속에 적힌 주석을 추출해서 그대로 실행하기
본문 바로가기
IT 이야기/Linux 셸 스크립트

[Linux 셸 스크립트] 변환처리 - 018 HTML 파일에서 태그 속에 적힌 주석을 추출해서 그대로 실행하기

by 찬찬이 아빠 2021. 3. 5.
반응형
  1. 사용 명령어

(1) sed

(2) eval 

 

 

  2. 키워드 & 사용처

(1) 키워드

명령어, 변수 확장

 

(2) 사용처

파일에 적힌 문자열을 추출해서 명령어로 실해앟고 싶을 때 사용합니다.

 

  3. 실행 예제
$ ./eval.sh
Fri Mar 5 17:35:20 JST 2021
-rw-rw-r--. 1 user1 user1 11968 Oct 26 12:32 myapp.log

 

 

  4. 스크립트

#!/bin/sh

 

filename="myapp.log"

eval $(sed -n "s/<code>\(.*\)<\/code>/\1/p" command.htm)

 

 

  5. 해설

이 스크립트는 command.htm 파일 안에 적힌 <code> 태그를 추출해서 그 요소를 명령어로 실행합니다.

 

command.htm 파일 내용은 아래와 같습니다.

<html>
<head><title>Code List</title></head>

<body>
<p>This is a sample code.</p>
<code>date; ls -l $filename</code>

</body>
</html>

 

스크립트에서는 우선 <code> 태그 부분을 패턴 매치해서 추출합니다. 셸 스크립트에서 일치한 부분의 문자열을 추출하는 방법은 다양하지만 여기에서는 다음처럼 sed 명령어를 사용합니다.

sed -n "s/<code>\(.*\)<\/code>/\p" command.htm

 

sed 명령어의 -n 옵션은 처리 후에 패턴 스페이스 내용을 출력하지 않도록 하는 옵션입니다. 그대로는 아무것도 출력되지 않아서 의미가 없으므로 마지막에 p 플래그를 붙여서 일치했을 때만 패턴 스페이스를 출력하도록 지정합니다.

 

이런 -n 옵션과 p 플래그를 조합해서 sed 명령어로 치환하면 치환이 발생한 줄만 출력할 수 있습니다. sed 명령어에서 자주 쓰는 방식이므로 기억해두기 바랍니다.

 

그럼 이번에는 일치한 줄 중 <code> 태그 부분만 추출하고 싶으므로 후방참조 \1을 사용합니다. sed 명령어의 일치 확인에서 ()로 둘러싼 부분은 앞에서부터 순서대로 \1, \2, \3...으로 참조할 수 있습니다. 여기에서 <code> 안에 임의의 문자열 .*를 ()로 둘러싸서 \1로 추출합니다. \1 부분이 실행하고 싶은 명령어 문자열이 됩니다.

 

그럼 sed 정규표현식은 후방참조하는 부분의 괄호를 ()가 아니라 \(\)를 사용하므로 이 예제에서도 \(\)를 씁니다.

 

이걸로 명령어 문자열을 추출했으므로 eval로 변수 확장을 해서 명령어를 실행합니다. eval은 인수로 넘어온 문자열을 변수 확장해서 명령어로 실행합니다. 여기서 sed 명령어 출력은 다음과 같은 문자열입니다.

date; l -l $filename

 

eval 명령어에 이 문자열을 인수로 넘기면 셸 변수 filename이 치환되어 결과로 이런 코드가 실행됩니다.

date; ls -l myapp.log

 

이렇게 eval 명령어를 사용하면 셸 스크립트 코드 자체를 동적으로 생성해서 실행할 수 있습니다.

 

한편 eval 명령어는 사용법에 따라서는 메타프로그래밍처럼 쓸 수도 있어 편리합니다. 하지만 텍스트 문자열을 그냥 명령어로 실행하므로 사용법에 따라서는 악의적인 코드가 실행될 수 있으니 주의해야 합니다.

 

예를 들어 사용자로부터 입력받은 문자열에는 공격 코드가 들어 있을 수도 있습니다. 이렇듯 시스템 외부에서 입력받은 값을 부주의하게 eval로 실행하는 행위는 절대로 하면 안됩니다. OS 명령어 인젝션 같은 보안 문제가 발생하게 됩니다.

 

 

<주의사항>

이 예제에서 sed로 <code> 태그를 처리하므로 다음과 같이 <code> 태그 안에 줄바꿈이 있으면 제대로 동작하지 않습니다.

<code>
  date; ls -l $filename
</code>

 

eval 명령어는 인수 문자열을 명령어로 해석해서 그대로 실행해버리므로 입력값에 주의해야 합니다. 예를 들어 만약 다음과 같은 문자열이 <code> 태그에 있다고 합시다.

rm -rf ~/*

이 스크립트를 실행하면 ~가 홈 디렉터리로 확장되어 실행한 사람의 홈 디렉터리 내부를 전부 삭제해버립니다. eval로 실행하는 스크립트를 만들 때에는 우선 eval 부분을 echo로 바꿔서 실행할 때 실제로 어떤 명령어 내용이 나오는지 확인해봅시다. 또한 사용자 입력값처럼 뭐가 들어 있을지 모르는 문자열을 eval로 실행하는 행위는 위험합니다.

 

 

참고서적 : 유닉스 리눅스 셸 스크립트 예제 사전

반응형

댓글