[Linux 셸 스크립트] 텍스트 처리 - 070 파일 앞머리의 셔뱅(shebang, #!/bin/sh 등)을 추출해서 스크립트에 따라 확장자 붙이기
본문 바로가기
IT 이야기/Linux 셸 스크립트

[Linux 셸 스크립트] 텍스트 처리 - 070 파일 앞머리의 셔뱅(shebang, #!/bin/sh 등)을 추출해서 스크립트에 따라 확장자 붙이기

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

(1) head

(2) mv

 

  2. 키워드 & 사용처

(1) 키워드

셔뱅, shebang, 확장자, 첫줄

 

(2) 사용처

확장자가 없는 스크립트 파일에 자동으로 확장자를 부여하고 싶을 때 사용합니다.

 

  3. 실행 예제
$ ./shebang.sh script
'script' -> 'script.sh'

$ ./shebang.sh sample1
'sample1' -> 'sample1.pl'

 

 

  4. 스크립트

#!/bin/sh

 

# 대상 스크립트 파일이 있는지 확인

if [ ! -f "$1" ]; then           

    echo "지정한 파일을 찾지 못했습니다: $1" >&2

    exit 1

fi

 

# 파일 첫 줄 읽음

headline=$(head -n 1 "$1")           

 

# 파일 첫 줄에 따라 확장자를 판정해서 부여함

case "$headline" in                   

    */bin/sh|*bash*)

        mv -v "$1" "${1}.sh"

        ;;

    *perl*)

        mv -v "$1" "${1}.pl"

        ;;

    *ruby*)

        mv -v "$1" "${1}.rb"

        ;;

    *)

        echo "Unknown Type: $1"

esac

 

 

  5. 해설

이 스크립트는 스크립트 파일 첫 줄을 읽어서 사용된 언어에 대응하는 확장자를 파일명에 부가합니다.

 

관례적으로 스크립트 파일은 해당 언어에 대응하는 확장자를 파일명에 사용합니다. 일반적으로 사용하는 확장자는 다음 표와 같습니다.

확장자 언어
sh sh, bash
pl Perl
rb Ruby
py Python
php PHP

하지만 확장자는 어디까지나 관례이므로 셸 스크립트를 포함해서 스크립트 파일은 확장자가 없더라도 동작합니다. 따라서 셸 스크립트를 작성할 때 .sh를 붙이지 않는 사람도 있습니다.

 

여러분이 관리하는 시스템에도 확장자가 없는 스크립트가 존재할지도 모릅니다. 파일명 만으로도 어떤 언어로 만들어졌는지 알 수 있도록 그런 스크립트의 확장자를 일괄적으로 추가하고 싶을 때가 있을 겁니다. 그럴 때 이 예제를 사용하면 좋습니다.

 

셸 스크립트의 첫 줄은 반드시 #!로 시작합니다.

#!/bin/sh

이를 셔뱅(Shebang)이라고 합합니다.유닉스에서는 파일을 실행할 때 그 파일이 기계어로 작성된 파일이라면 그대로 실행합니다. 그렇지 않으면 파일 첫 줄을 읽어서 #! 뒤에있는 명령어를 실행합니다. 위 예에서는 /bin/sh가 실행되므로 셸 스크립트로 동작하게 됩니다.

 

이런 셔뱅의 동작을 이해하기 위해 다음과 같은 실험을 해봅시다.

 

C언어 등으로 작성된 실행 파일(기계어 파일)과 셸 스크립트 파일은 실행하기 위한 최소 퍼미션이 다릅니다. C 언어 등으로 만든 실행 파일은 읽기 퍼미션이 없어도 실행 권한이 있으면 실행됩니다.

 

C언어로 작성한 실행 파일은 실행 비트만으로도 실행이 가능합니다.

$ chmod 100 a.out
$ ls -l a.out
---x------ 1 park park 6425 Apr 7 16:40 a.out*
$ ./a.out
Hello, World.

 

셸 스크립트 파일은 일반 사용자로 실행할 때는 실행 권한만으로는 실행되지 않고 반드시 읽기 권한도 있어야 합니다.

$ chmod 100 ptest.sh
$ ls -l ptest.sh
---x------ 1 park park 29 Apr 7 17:30 ptest.sh*
$ p./ptest.sh
/bin/sh: ./ptest.sh: Permission denied

 

sh ./ptest.sh라고 해석되므로 ptest.sh에 읽기 권한이 있어야만 합니다(단, root 사용자는 그대로 실행할 수 있습니다).

 

예제에서는 이 셔뱅을 봐서 파일 종류를 판별해 확장자를 부여합니다.

 

우선 에서는 대상 스크립트 파일을 확인합니다. test 명령어 -f 연산자로 파일이 존재하는지 확인해서 부정 연산자 !를 사용해 파일이 존재하지 않을 때 에러를 표시하고 종료합니다.

 

이어서 에서는 head 명령어로 파일 첫 줄을 추출해서 셸 변수 headline에 저장합니다. head 명령어는 파일 앞부분 부터 읽는 명령어로 -n 옵션을 사용하면 지정한 줄 수만 추출할 수 있습니다. 여기서 -n 1을 지정해서 첫 줄만 추출해서 셔뱅만 취득합니다.

 

에서 case문을 사용해 파일 종류를 판단합니다. mv 명령어를 이용해서 */bin.sh | *bash*와 일치하면(sh 또는 bash 스크립트) 확장자를 .sh로, *perl*와 일치하면 .pl로, *ruby*와 일치하면 .rb로 파일명을 변경합니다. 명령어 뒤에 *를 붙이는 것은 옵션 지정을 위해 뒤에 스페이스나 옵션이 이어져도 일치하도록 하기 위함입니다.

 

그리고 확장자 변경 mv 명령어에 -v 옵션을 써서 변경 전후 파일명을 표시합니다.

 

case문 마지막에서 *를 이용해 지금까지 일치하지 않은 그 외의 파일은 "Unknown Type:" 이라고 표시하고 파일명을 변경하지 않습니다.

 

 

<주의사항>

이 스크립트는 펄, 루비, sh, bash에만 대응합니다. 만약 루비가 /usr/bin/perl/ruby 같은 경로에 설치되었다면 오동작하게 됩니다.

 

이미 확장자가 설정되어 있는지 확인하지 않으므로 상황에 따라서는 ptest.pl.pl처럼 확장자가 이중으로 지정될 수도 있습니다.

 

파일 종류를 알 수없을 때는file 명령어가 편리합니다. file 명령어는 다음처럼 파일을 인수로 지정해서 그 파일이 무엇인지 판단해서 표시합니다.

$ file /usr/bin/startx
/usr/bin/startx: POSIX shell script text executable

$ file network.dat
network.dat: tcpdump capture file (little-endian) - version 2.4(Ethernet, capture length 65535)

 

위 예에서 첫 번째 startx 파일은 셸 스크립트, 두 번째 network.dat 파일은 tcpdump한 패킷 캡쳐 파일입니다. 그리고 file 명령어는 "'매직 파일'이라는 일종의 '파일 사전'이 있어서 이것을 보고 파일 종류를 판단합니다.

 

head 명령어와 반대로 파일 끝에서부터 읽는 tail 명령어도 있습니다.

 

 

 

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

반응형

댓글