34.2. 쉘 래퍼(Shell Wrappers)

"래퍼"란 시스템 명령어나 유틸리티들을 해당 매개변수들과 함께 쉘 스크립트로 만들어 두는 것을 말합니다. 명령어줄에서 아주 복잡하게 부를 명령어를 스크립트로 만들어 두면 실행 시킬 때 아주 간단해 집니다. 특히 sedawk에 이 쉘 래퍼를 쓰면 아주 좋습니다.

sed awk 스크립트는 명령어 줄에서 sed -e 'commands'라고 치거나 awk 'commands'이라고 쳐서 실행 시킬 수 있습니다. 이런 스크립트를 Bash 스크립트 안에서 사용하게 되면 좀 더 간단하게 쓸 수 있고 "재사용"할 수 있습니다. 예를 들어 sed의 출력과 awk의 입력을 파이프로 연결하는 것처럼 sedawk의 기능을 연결해서도 쓸 수도 있습니다. 저장된 실행 파일이라면 다시 치는 불편함 없이 원래 형태나 약간 변경된 형태로 계속 실행 시킬수가 있습니다.

예 34-1. 쉘 래퍼(shell wrapper)

#!/bin/bash

# 파일에서 빈 줄을 지워주는 간단한 스크립트.
# 인자 확인 안 함.

# 명령어줄에서 
#    sed -e '/^$/d' filename
# 이라고 하는 것과 똑같음.

sed -e /^$/d "$1"
# '-e'는 다음에 나오는 것을 "편집" 명령어로 해석(여기서는 넣어도 되고 안 넣어도 됨).
# '^'는 줄 처음, '$'는 줄 끝.
# 줄 처음과 줄 끝 사이에 아무 것도 없는 것(빈 줄)과 일치.
# 'd' 는 삭제 명령어.

#  명령어줄 인자를 쿼우트 해 주면 파일이름에
#+ 공백문자나 특수문자가 들어가도 상관없습니다.

exit 0

예 34-2. 조금 복잡한 쉘 래퍼(shell wapper)

#!/bin/bash

# "subst", 파일에서 어떤 패턴을 다른 패턴으로 바꿔주는 스크립트.
# 즉, "subst Smith Jones letter.txt".

ARGS=3
E_BADARGS=65   # 필요한 인자가 빠져있음.

if [ $# -ne "$ARGS" ]
# 스크립트로 넘겨진 인자의 갯수를 확인(항상 이렇게 하세요).
then
  echo "사용법: `basename $0` old-pattern new-pattern filename"
  exit $E_BADARGS
fi

old_pattern=$1
new_pattern=$2

if [ -f "$3" ]
then
    file_name=$3
else
    echo "\"$3\" 은 없는 파일입니다."
    exit $E_BADARGS
fi

# 여기가 가장 중요한 부분입니다.
sed -e "s/$old_pattern/$new_pattern/g" $file_name
# 's'는 sed의 치환(substitution) 명령어이고,
# /pattern/ 은 주소 매칭을 실행시킵니다.
#  전역(global) 플래그인 "g"를 쓰면 단지 첫번째 일치하는 $old_pattern만 
#+ 치환시키지 않고 각 줄에서 일치하는 "모든" $old_pattern을 치환시킵니다.
# 더 자세한 설명은 'sed' 문서를 읽어보세요.

exit 0    # 스크립트의 실행이 성공이라면 0을 리턴.

예 34-3. awk 스크립트 쉘 래퍼(shell wrapper)

#!/bin/bash

# 대상 파일에서 주어진 열을 다 더하기.

ARGS=2
E_WRONGARGS=65

if [ $# -ne "$ARGS" ] # 명령어줄 인자 수가 적당한지 확인.
then
   echo "사용법: `basename $0` filename column-number"
   exit $E_WRONGARGS
fi

filename=$1
column_number=$2

# 쉘 변수를 awk 에게 넘기는 것은 약간 까다롭습니다.
# 더 자세한 것은 awk 문서를 참고하세요.

# 여러줄짜리 awk 스크립트는    awk ' ..... '   처럼 부르면 됩니다.


# awk 스크립트 시작.
# -----------------------------
awk '

{ total += $'"${column_number}"'
}
END {
     print total
}     

' "$filename"
# -----------------------------
# awk 스크립트 끝.


#   쉘 스크립트에 내장된 awk 스크립트에게 쉘 변수를 넘기는 것은 
#   안전하지 않을 수가 있기 때문에, Stephane Chazelas 가 다음과 같은 대안을 
#   제안해 주었습니다:
#   ---------------------------------------
#   awk -v column_number="$column_number" '
#   { total += $column_number
#   }
#   END {
#       print total
#   }' "$filename"
#   ---------------------------------------


exit 0

하나로 된 만능 툴이나 스위스 군용 칼 같은 기능이 필요한 스크립트들을 위해 펄이 있습니다. 펄은 sedawk의 기능을 묶어 C 의 큰 서브셋으로 만듭니다. 모듈로 동작하며 객체 지향 프로그래밍에서 부엌 싱크대까지 모든 것을 지원합니다. 짧은 펄 스크립트는 쉘 스크립트 상에서 효과적으로 쓰일 수 있고, 펄이 쉘 스크립트를 완전히 대체할 수 있을 거란 얘기도 있지만 저자는 그렇게 생각하지 않습니다.

예 34-4. Bash 스크립트에 내장된 펄

#!/bin/bash

# 펄 스크립트보다 쉘 스크립트가 먼저 올 수 있습니다.
echo "\"$0\" 에서 내장된 펄 스크립트보다 먼저 등장."
echo "==============================================================="

perl -e 'print "내장된 펄 스크립트 부분.\n"'
# sed 처럼 펄도 "-e" 옵션을 씁니다.

echo "==============================================================="
echo "하지만, 스크립트에는 쉘이나 시스템 명령어가 올 수도 있습니다."

exit 0

심지어는 Bash 스크립트와 펄 스크립트를 한 파일에서 같이 쓸 수도 있습니다. 그 스크립트가 어떻게 불리냐에 따라 Bash 부분이 실행될지 펄 부분이 실행될지가 결정됩니다.

예 34-5. 하나로 묶인 Bash 스크립트와 펄 스크립트

#!/bin/bash
# bashandperl.sh

echo "스크립트의 Bash 쪽에서 보내는 축하 메세지."
# 이 다음에 Bash 명령어가 더 올 수 있습니다.

exit 0
# Bash 부분의 끝.

# =======================================================

#!/usr/bin/perl
# 이 부분은 -x 옵션을 줘야 실행됩니다.

print "스크립트의 펄 쪽에서 보내는 축하 메세지.\n";
# 이 다음에 펄 명령어가 더 올 수 있습니다.

# 펄 부분의 끝.

bash$ bash bashandperl.sh
스크립트의 Bash 쪽에서 보내는 축하 메세지.


bash$ perl -x bashandperl.sh
스크립트의 펄 쪽에서 보내는 축하 메세지.