9.1. 내부 변수(Internal Variables)

내장(Builtin) 변수

Bash 스크립트의 동작에 영향을 미치는 변수

$BASH

Bash 실행 파일의 경로로, 보통은 /bin/bash

$BASH_ENV

스크립트가 실행될 때 어디에서 bash 시작 파일을 읽을 것인지를 나타내는 환경 변수

$BASH_VERSINFO[n]

원소 갯수가 6개인 배열로, 현재 설치된 Bash 버전에 대한 정보를 담고 있습니다. 다음에 설명할 $BASH_VERSION 과 비슷하지만 좀 더 자세한 정보를 담고 있습니다.

# Bash 버전 정보:

for n in 0 1 2 3 4 5
do
  echo "BASH_VERSINFO[$n] = ${BASH_VERSINFO[$n]}"
done  

# BASH_VERSINFO[0] = 2                      # Major version no.
# BASH_VERSINFO[1] = 04                     # Minor version no.
# BASH_VERSINFO[2] = 21                     # Patch level.
# BASH_VERSINFO[3] = 1                      # Build version.
# BASH_VERSINFO[4] = release                # Release status.
# BASH_VERSINFO[5] = i386-redhat-linux-gnu  # Architecture
                                            # ($MACHTYPE 과 동일).

$BASH_VERSION

시스템에 설치된 Bash 버전

bash$ echo $BASH_VERSION
2.04.12(1)-release
	      

tcsh% echo $BASH_VERSION
BASH_VERSION: Undefined variable.
	      

어떤 쉘로 동작중인지 알아보려고 할 때 $BASH_VERSION 을 확인해 보는 것은 아주 좋은 방법입니다. 왜냐하면, $SHELL 로는 충분한 정보를 얻을 수 없기 때문입니다.

$DIRSTACK

디렉토리 스택의 내용(pushdpopd의 영향을 받음)

이 내장 변수는 dirs 명령어와 짝을 이룹니다.

$EDITOR

스크립트가 부르는 에디터로서, 보통은 viemacs입니다.

$EUID

"유효" 사용자 아이디 값

su에 의해 쓰일 현재 사용자의 유효 아이디 값.

경고

$EUID$UID와 반드시 같지 않습니다.

$FUNCNAME

현재 함수의 이름

xyz23 ()
{
  echo "$FUNCNAME now executing."  # xyz23 now executing.
}

xyz23

echo "FUNCNAME = $FUNCNAME"        # FUNCNAME =
                                   # 함수 밖에서는 널 값을 갖습니다.

$GLOBIGNORE

globbing 시 포함되지 않을 파일명 패턴들의 목록.

$GROUPS

현재 사용자가 속해 있는 그룹

/etc/passwd에 적혀 있는 현재 사용자의 그룹 아이디 값을 보여줍니다.

$HOME

사용자의 홈 디렉토리로, 보통은 /home/username (예 9-10 참고)

$HOSTNAME

hostname 명령어는 부팅시 init 스크립트에서 시스템 이름을 설정해 줍니다. 하지만 gethostname() 함수로 bash 내부 변수인 $HOSTNAME을 설정해 줄 수도 있습니다. 예 9-10을 참고하세요.

$HOSTTYPE

host type

$MACHTYPE과 마찬가지로 시스템 하드웨어를 알려줍니다.

bash$ echo $HOSTTYPE
i686
$IFS

입력 필드 구분자

디폴트는 공백문자(빈칸, 탭, 뉴라인)지만 콤마로 구분된 데이타 파일을 파싱하려는 경우처럼 변경이 가능합니다. $*$IFS의 첫번째 문자를 사용하는 것에 주의하세요. 예 6-1 참고.

bash$ echo $IFS | cat -vte
$


bash$ bash -c 'set w x y z; IFS=":-;"; echo "$*"'
w:x:y:z
	      

경고

$IFS 는 빈 칸을 다른 문자들과는 다르게 처리합니다.

예 9-1. $IFS 와 빈 칸

#!/bin/bash
# $IFS 는 공백문자를 다른 문자들과 다르게 처리합니다.

output_args_one_per_line()
{
  for arg
  do echo "[$arg]"
  done
}

echo; echo "IFS=\" \""
echo "-------"

IFS=" "
var=" a  b c   "
output_args_one_per_line $var  # output_args_one_per_line `echo " a  b c   "`
#
# [a]
# [b]
# [c]


echo; echo "IFS=:"
echo "-----"

IFS=:
var=":a::b:c:::"               # 위와 같지만 ":" 를 " "로 바꿔줍니다.
output_args_one_per_line $var
#
# []
# [a]
# []
# [b]
# [c]
# []
# []
# []

# awk 의 "FS" 필드 구분자도 위와 같은 동작을 합니다.

# Thank you, Stephane Chazelas.

echo

exit 0

(S. C. 에게 정확한 설명과 예제에 감사.)

$IGNOREEOF

EOF 무시: 로그 아웃하기 전에 몇 개의 end-of-files (control-D)를 무시할 것인지.

$LC_COLLATE

주로 .bashrc/etc/profile 에서 세트되는 이 변수는 파일명 확장이나 패턴 매칭시의 대조(collation) 순서를 제어합니다. 이 값이 잘못 처리되면 파일명 globbing시 원치 않는 결과를 가져 올 수 있습니다.

참고: Bash 2.05 이후로, 파일명 globbing 은 대괄호에 들어 있는 문자 범위에 나타나는 대소문자를 더 이상 구분하지 않습니다. 예를 들어, ls [A-M]*File2.txtfile1.txt 모두와 일치될 것입니다. 자신만의 대괄호 매칭 동작을 원래대로 바꾸려면 /etc/profile이나 ~/.bashrc등에 export LC_COLLATE=C 라고 해서 LC_COLLATEC로 세트해 주면 됩니다.

$LC_CTYPE

이 내부 변수는 globbing 과 패터 매칭의 문자 해석을 제어합니다.

$LINENO

쉘 스크립트에서 이 변수가 들어 있는 줄의 줄번호를 나타내는데, 스크립트에서 쓰일 때만 의미가 있고, 주로 디버깅에 쓰입니다.

last_cmd_arg=$_  # 저장.

echo "$LINENO 번째 줄, 변수 \"v1\" = $v1"
echo "처리된 마지막 명령어 인자 = $last_cmd_arg"

$MACHTYPE

머신 종류

시스템 하드웨어를 구분해 줍니다.

bash$ echo $MACHTYPE
i686-debian-linux-gnu
$OLDPWD

바로 전 작업 디렉토리 ("OLD-print-working-directory")

$OSTYPE

운영 체제 종류

bash$ echo $OSTYPE
linux-gnu
$PATH

실행 파일의 경로, 보통은 /usr/bin/, /usr/X11R6/bin/, /usr/local/bin, 등등.

명령어가 주어지면 쉘은 실행 파일들을 위한 경로에 들어있는 디렉토리들에 대해서 자동으로 해쉬 테이블 탐색을 수행합니다. 경로에는 환경 변수인 $PATH에 디렉토리들이 콜론으로 구분되어 들어 있습니다. 보통 $PATH 정의는 /etc/profile이나 ~/.bashrc에 들어 있습니다(27장 참고).

bash$ echo $PATH
/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/sbin:/usr/sbin

PATH=${PATH}:/opt/bin 라고 하면 /opt/bin을 현재 경로에 추가 시킵니다. 이렇게 하면 경로에 임시로 디렉토리를 적절하게 추가할 수 있습니다. 스크립트가 끝나면 원래 $PATH 로 복구됩니다(스크립트같은 자식 프로세스는 부모 프로세스인 쉘의 환경 변수를 바꿀 수 없습니다).

참고: 보통은 현재 "작업 디렉토리"를 나타내는 ./은 보안상의 이유로 $PATH에서 제외시킵니다.

$PIPESTATUS

마지막으로 실행된 파이프의 종료 상태. 아주 재미있는 것은, 이 결과와 마지막으로 실행된 명령어의 종료 상태가 똑같지는 않다는 것입니다.

bash$ echo $PIPESTATUS
0

bash$ ls -al | bogus_command
bash: bogus_command: command not found
bash$ echo $PIPESTATUS
141

bash$ ls -al | bogus_command
bash: bogus_command: command not found
bash$ echo $?
127
	      

$PPID

어떤 프로세스의 부모 프로세스의 프로세스 아이디(pid)를 $PPID이라고 합니다. [1]

이것들을 pidof 명령어와 비교해 보세요.

$PS1

명령어줄에서 볼 수 있는 메인 프롬프트.

$PS2

2차 프롬프트로, 추가적인 입력이 필요할 때 ">" 로 표시됩니다.

$PS3

3차 프롬프트로 select 루프문에서 표시됩니다(예 10-27 참고).

$PS4

4차 프롬프트로, 스크립트에 -x 옵션이 걸려서 실행될 때 스크립트의 매 줄마다 "+"로 표시됩니다.

$PWD

작업 디렉토리(현재 있는 디렉토리)

내장 명령인 pwd와 비슷합니다.

#!/bin/bash

E_WRONG_DIRECTORY=73

clear # 화면 정리.

TargetDirectory=/home/bozo/projects/GreatAmericanNovel

cd $TargetDirectory
echo "$TargetDirectory 디렉토리의 오래된 파일을 지웁니다."

if [ "$PWD" != "$TargetDirectory" ]
then    # 실수로 다른 디렉토리를 지우지 않게 합니다.
  echo "지울 디렉토리가 아닙니다!"
  echo "$TargetDirectory 디렉토리가 아니라 $PWD 디렉토리입니다,"
  echo "취소합니다!"
  exit $E_WRONG_DIRECTORY
fi  

rm -rf *
rm .[A-Za-z0-9]*    # 도트 파일 삭제.
# 이름이 여러개의 점으로 시작하는 파일도 지우려면 이렇게 하세요.   rm -f .[^.]* ..?*   
# (shopt -s dotglob; rm -f *)   라고 해도 됩니다.
# 지적해 줘서 고마워요. S.C.

# 파일이름에는 "/"를 제외하고 0 - 255 사이의 모든 문자가 들어갈 수 있습니다.
# 이상한 문자로 시작하는 파일을 지우는 것은 연습문제로 남겨 놓습니다.

# 필요하다면 다른 작업을 하세요.

echo
echo "끝."
echo "$TargetDirectory 디렉토리의 오래된 파일을 모두 삭제했습니다."
echo


exit 0

$REPLY

read에 변수가 안 주어졌을 때 저장되는 기본값이고, select 메뉴에서는 변수의 값이 아니라 선택한 숫자가 저장됩니다.

#!/bin/bash

echo
echo -n "제일 좋아하는 야채가 뭐에요? "
read

echo "제일 좋아하는 야채가 $REPLY 군요."
# REPLY 는 가장 최근의 "read"가 변수 없이 주어졌을 때 그 값을 담고 있습니다.

echo
echo -n "제일 좋아하는 과일은요? "
read fruit
echo "당신이 제일 좋아하는 과일은 $fruit 지만,"
echo "\$REPLY 의 값은 여전히 $REPLY 네요."
# $fruit 변수가 "read"의 값을 가져가 버렸기 때문에 $REPLY 는 여전히
# 앞에서 설정된 값을 갖고 있습니다.

echo

exit 0

$SECONDS

스크립트가 얼마나 돌았는지를 나타내는 초 단위 시간.

#!/bin/bash

ENDLESS_LOOP=1
INTERVAL=1

echo
echo "스크립트를 끝내려면 Control-C 를 누르세요."
echo

while [ $ENDLESS_LOOP ]
do
  if [ "$SECONDS" -eq 1 ]
  then
    units=second
  else  
    units=seconds
  fi

  echo "이 스크립트는 $SECONDS $units 동안 돌고 있습니다."
  sleep $INTERVAL
done


exit 0

$SHELLOPTS

현재 켜 있는 쉘 옵션들의 목록으로서 읽기 전용 변수

$SHLVL

쉘 레벨로 Bash 가 얼마나 깊이 중첩되어 있는지를 나타냄. 만약에 명령어줄에서 $SHLVL 이 1 이었다면 스크립트에서는 2 가 됩니다.

$TMOUT

$TMOUT 환경 변수를 0 이 아닌 값 time으로 설정해 놓으면 그 시간이 지난 다음에는 로그아웃이 됩니다.

참고: 불행하게도 이 변수는 콘솔상의 쉘 프롬프트나 엑스텀(한텀)에서만 동작합니다. 예를 들어, read 문에서 $TMOUT을 같이 쓰고 싶겠지만 실제로는 제대로 동작하지 않습니다.(ksh 버전에서는 read의 타임아웃이 제대로 동작한다고 보고된 바 있습니다).

타임 아웃을 쉘 스크립트에서 구현할 수는 있으나 그렇게 효과적이지 않습니다. 한가지 가능한 방법은, 타임 아웃이 났을 때 타이밍 루프가 스크립트에게 시그널을 보내도록 세팅해야 하고 타이밍 루프가 발생시킨 (예 30-4 참고) 인터럽트를 처리할 시그널 처리 루틴도 만들어야 합니다, 휴~~.

예 9-2. 타임 아웃 처리 입력

#!/bin/bash
# timed-input.sh

# TMOUT=3            스크립트에서는 쓸모가 없습니다.

TIMELIMIT=3  # 여기서는 3초, 다른 값으로 세트할 수 있습니다.

PrintAnswer()
{
  if [ "$answer" = TIMEOUT ]
  then
    echo $answer
  else       # 두 번의 인스턴스를 구분하기 위해서.
    echo "제일 좋아하는 야채는 $answer 이군요."
    kill $!  # 백그라운드에서 도는 TimerOn 함수가 더 이상 필요없기 때문에 kill 시킴.
             # $! 는 백그라운드에서 돌고 있는 가장 최근 작업의 PID 입니다.
  fi

}  



TimerOn()
{
  sleep $TIMELIMIT && kill -s 14 $$ &
  # 3초를 기다리고 알람 시그널(sigalarm)을 스크립트에 보냄.
}  

Int14Vector()
{
  answer="TIMEOUT"
  PrintAnswer
  exit 14
}  

trap Int14Vector 14   # 타이머 인터럽트(14)는 우리 의도대로 타임아웃을 처리함.

echo "제일 좋아하는 야채가 뭐죠? "
TimerOn
read answer
PrintAnswer


# 이는 분명히 타임아웃 입력에 대한 미봉책입니다만,
# Bash 로 할 수 있는 최선을 다한 것입니다.
# (독자들에게 도전: 더 나은 해결책을 제시해 보세요.)

# 더 우아한 다른 것이 필요하다면 C 나 C++ 의 'alarm'이나 'setitimer' 같은
# 적당한 라이브러리 함수를 써서 구현하기 바랍니다.

exit 0

stty를 쓴 다른 방법.

예 9-3. 타임 아웃 처리 입력, 한 번 더

#!/bin/bash
# timeout.sh

# Stephane Chazelas 작성.
# 이 문서의 저자가 수정.

INTERVAL=5                # 타임아웃 인터벌

timedout_read() {
  timeout=$1
  varname=$2
  old_tty_settings=`stty -g`
  stty -icanon min 0 time ${timeout}0
  eval read $varname      # 아니면 그냥     read $varname
  stty "$old_tty_settings"
  # "stty" 맨 페이지 참조.
}

echo; echo -n "이름이 뭐죠? 빨리 대답해요! "
timedout_read $INTERVAL your_name

# 모든 터미널 타입에서 동작하지 않을 수도 있습니다.
# 최대 타임아웃은 어떤 터미널이냐에 달려있습니다.
# (보통은 25.5 초).

echo

if [ ! -z "$your_name" ]  # 타임아웃 전에 입력이 있다면...
then
  echo "아하, 이름이 $your_name 군요."
else
  echo "타임아웃."
fi

echo

# 이 스크립트는 "timed-input.sh" 스크립트와 약간 다르게 동작하는데,
# 키가 눌릴 때마다 타임아웃 카운터가 리셋됩니다.

exit 0
$UID

사용자 아이디 값

/etc/passwd에 저장되어 있는 현재 사용자의 사용자 식별 숫자

비록 su에 의해서 임시로 다른 사용자로 인식되더라도 현재 사용자의 실제 아이디를 나타냅니다. $UID는 읽기만 되는 변수로 명령어 줄이나 스크립트에서 변경할 수 없습니다. 그리고, id 내장 명령과 짝을 이룹니다.

예 9-4. 내가 루트인가?

#!/bin/bash
# am-i-root.sh:   내가 루트야 아니야?

ROOT_UID=0   # 루트 $UID는 0.

if [ "$UID" -eq "$ROOT_UID" ]  # Will the real "root" please stand up?
then
  echo "루트네요."
else
  echo "그냥 보통 사용자에요.(그래도 당신 어머니는 있는 그대로의 당신을 사랑하신답니다)."
fi

exit 0


# ============================================================= #
# 스크립트가 이미 종료됐기 때문에 밑의 코드는 실행되지 않습니다.

# 루트인지 알아내는 다른 방법:

ROOTUSER_NAME=root

username=`id -nu`
if [ "$username" = "$ROOTUSER_NAME" ]
then
  echo "루티 투트 투트(Rooty, toot, toot), 당신은 루트 사용자군요."
else
  echo "그냥 보통 사람이군요."
fi

exit 0

예 2-2 참고.

참고: $ENV, $LOGNAME, $MAIL, $TERM, $USER, $USERNAME은 bash 내장 명령아닙니다. 하지만 종종 bash 시스템 구동 파일에서 환경 변수로 설정이 됩니다. 사용자의 로긴 쉘을 나타내는 $SHELL/etc/passwd를 참고해 설정되거나 "init" 스크립트에서 설정되고, 역시 bash 내장명령어가 아닙니다.

tcsh% echo $LOGNAME
bozo
tcsh% echo $SHELL
/bin/tcsh
tcsh% echo $TERM
rxvt

bash$ echo $LOGNAME
bozo
bash$ echo $SHELL
/bin/tcsh
bash$ echo $TERM
rxvt
	      

위치 매개변수(Positional Parameters)

$0, $1, $2, etc.

위치 매개변수로서, 명령어줄에서 스크립트로 넘겨지거나 함수로 넘겨지거나 set 명령어로 강제로 설정됨(예 5-5예 11-10 참고).

$#

명령어줄 인자 [2] 의 갯수나 위치 매개변수들(예 34-2 참고)

$*

한 낱말로 표시되는 위치 매개변수들 모두

$@

$*과 똑같지만 각 매개변수는 쿼우트된 문자열로 취급됩니다. 즉, 해석되거나 확장없이 있는 그대로 넘겨집니다. 그 결과로 각 인자는 각각이 서로 다른 낱말로 구분돼서 표시됩니다.

예 9-5. arglist: $* 과 $@ 로 인자를 나열하기

#!/bin/bash
# 이 스크립트를 부를 때 "one two three" 같은 인자를 줘서 부르세요.

E_BADARGS=65

if [ ! -n "$1" ]
then
  echo "사용법: `basename $0` argument1 argument2 etc."
  exit $E_BADARGS
fi  

echo

index=1

echo "\"\$*\" 로 인자를 나열하기:"
for arg in "$*"  # "$*" 를 쿼우트하지 않으면 제대로 동작하지 않습니다.
do
  echo "Arg #$index = $arg"
  let "index+=1"
done             # $* 는 모든 인자를 하나의 낱말로 봅니다.
echo "전체 인자 목록은 하나의 낱말로 나타납니다."

echo

index=1

echo "\"\$@\" 로 인자를 나열하기:"
for arg in "$@"
do
  echo "Arg #$index = $arg"
  let "index+=1"
done             # $@ 는 인자들을 분리된 낱말로 봅니다.
echo "전체 인자 목록은 분리된 낱말로 나타납니다."

echo

exit 0

특수 매개변수인 $@에는 쉘 스크립트로 들어오는 입력을 필터링하는 툴로서 쓰입니다. cat "$@"은 자신의 매개변수를 표준입력이나 파일에서 받아 들일 수 있습니다. 예 12-17을 참고하세요.

경고

$*$@은 가끔 $IFS의 설정값에 따라 일관성이 없고 이상한 동작을 합니다.

예 9-6. 일관성 없는 $*$@의 동작

#!/bin/bash

# 쿼우트 여부에 따라 이상하게 동작하는 
# Bash 내부 변수 "$*"와 "$@".
# 낱말 조각남과 라인피드가 일관성 없이 처리됩니다.

# 이 예제 스크립트는 Stephane Chazelas 가 제공하고,
# 본 문서의 저자가 약간 수정했습니다.


set -- "첫번째 인자" "두번째" "세번째:인자" "" "네번째: :인자"
# 스크립트의 인자를 $1, $2 등으로 세팅.

echo

echo 'IFS 는 그대로, "$*"'
c=0
for i in "$*"               # 쿼우트
do echo "$((c+=1)): [$i]"   # 매 인스턴스마다 똑같음.
                            # 인자 에코.
done
echo ---

echo 'IFS 는 그대로, $*'
c=0
for i in $*                 # 쿼우트 안 함
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS 는 그대로, "$@"'
c=0
for i in "$@"
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS 는 그대로, $@'
c=0
for i in $@
do echo "$((c+=1)): [$i]"
done
echo ---

IFS=:
echo 'IFS=":", "$*"'
c=0
for i in "$*"
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS=":", $*'
c=0
for i in $*
do echo "$((c+=1)): [$i]"
done
echo ---

var=$*
echo 'IFS=":", "$var" (var=$*)'
c=0
for i in "$var"
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS=":", $var (var=$*)'
c=0
for i in $var
do echo "$((c+=1)): [$i]"
done
echo ---

var="$*"
echo 'IFS=":", $var (var="$*")'
c=0
for i in $var
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS=":", "$var" (var="$*")'
c=0
for i in "$var"
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS=":", "$@"'
c=0
for i in "$@"
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS=":", $@'
c=0
for i in $@
do echo "$((c+=1)): [$i]"
done
echo ---

var=$@
echo 'IFS=":", $var (var=$@)'
c=0
for i in $var
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS=":", "$var" (var=$@)'
c=0
for i in "$var"
do echo "$((c+=1)): [$i]"
done
echo ---

var="$@"
echo 'IFS=":", "$var" (var="$@")'
c=0
for i in "$var"
do echo "$((c+=1)): [$i]"
done
echo ---

echo 'IFS=":", $var (var="$@")'
c=0
for i in $var
do echo "$((c+=1)): [$i]"
done

echo

# 이 스크립트를 ksh 이나 zsh -y 로 실행해 보세요.

exit 0

참고: $@$*는 큰따옴표로 쿼우트 됐을 때만 달라집니다.

예 9-7. $IFS 가 비어 있을 때 $*$@

#!/bin/bash

# $IFS 가 빈 상태로 세트됐다면,
# "$*" 와 "$@" 는 위치 매개변수를 우리가 생각하는대로 에코하지 않습니다.

mecho ()       # 위치 매개변수 에코.
{
echo "$1,$2,$3";
}


IFS=""         # 빈 상태로 세트.
set a b c      # 위치 매개변수.

mecho "$*"     # abc,,
mecho $*       # a,b,c

mecho $@       # a,b,c
mecho "$@"     # a,b,c

# $IFS 가 비어 있을 경우에 $* 와 $@ 의 동작은
# Bash 나 sh 의 버전에 따라 달라지기 때문에
# 스크립트에서 이 "기능"에 쓰는 것은 권장하지 않습니다.


# Thanks, S.C.

exit 0

다른 특수 매개변수

$-

스크립트로 넘겨진 플래그들

경고

원래 ksh에서 쓰던 것을 bash에서 채택한 것인데 불행히도 잘 동작하지 않는 것 같습니다. 스크립트 자신이 대화형인지 아닌지 스스로 확인하려고 하는 경우에나 쓸만합니다.

$!

백그라운드로 돌고 있는 가장 최근 작업의 PID (process id)

$_

바로 이전에 실행된 명령어의 제일 마지막 인자로 설정되는 특수 변수.

예 9-8. 밑줄 변수(underscore variable)

#!/bin/bash

echo $_         # /bin/bash
# 스크립트를 돌리기 위해 실행된 /bin/bash. 

du >/dev/null   # 명령어 출력이 없음.
echo $_         # du

ls -al          # 명령어 출력이 없음.
echo $_         # -al  (마지막 인자)

:
echo $_         # :
$?

명령어나 함수, 스크립트 자신의 종료 상태(예 23-3 참고).

$$

스크립트 자신의 프로세스 아이디로 보통 임시 파일 이름을 만들 때 사용합니다(예 A-8예 30-5, 예 12-23 참고).

주석

[1]

현재 돌고 있는 스크립트의 pid 는 $$ 입니다.

[2]

"인자"(argument)나 "매개변수" (parameter)는 흔히 서로 바꿔서 쓰기 때문에 이 문서에서는 스크립트나 함수로 넘겨지는 변수를 나타내는 같은 의미로 쓰입니다.

'unix and linux' 카테고리의 다른 글

Why I love Perl  (0) 2008.02.20
bash 스트링 조작하기  (0) 2008.01.18
rotatelog.c 버그 수정해놓기  (0) 2008.01.16
getopt() 함수  (0) 2008.01.16
ssldump 설치하기  (0) 2008.01.04
Posted by '김용환'
,

bash shell

paper and essay 2008. 1. 18. 08:20

Bash Shell and Beyond

By William Park

Series Introduction

In this monthly series, I will try to expose the power of the Bash shell. In particular, the readers will be introduced to Bash.Diff which is a collection of my patches incorporating many ideas from Ksh, Zsh, Awk, Python, and other languages.

Each article will focus on one theme or feature, which is not normally thought of in shell context. I will also make liberal use of shell functions, standard builtins, dynamically loadable builtins, and advanced features patched into Bash, in a format that can be easily sourced and maintained.

string.sh

In C, <string.h> defines strcat(3), strcpy(3), strlen(3), and strcmp(3) for string concatenation, copy, size, and test operations respectively. Such basic operations are needed constantly when programming in any language, and shell scripting is no exception.

strcat() and strcpy()

For string copy and concatenation, you would do something like
    a=abc
    a=${a}'123'			# a=abc123
in shell. This is simple variable assignment. However, you can't have variable reference on the left-hand side (LHS) of '='. You have to either type the LHS variable name explicitly as above, or use eval, as in
    x=a
    eval "$x=abc"
    eval "$x=\${$x}'123'"
to parse the "..." expressions twice. It quickly becomes painful to call eval all the time, especially when the variable names are parsed from a file or a string.

What is needed is a shell version of C functions strcat(3) and strcpy(3) which can be called with equal ease and simplicity. So, here they are:

    strcat ()		# var+=string
    {
	local _VAR=$1 _STRING=$2 _a _b

	case $#.$3 in
	    2.) ;;
	    3.*:*) _a=${3%:*} _b=${3#*:}
		set -- `python_to_shell_range "$_a" "$_b" ${#_STRING}`
		_STRING=${_STRING:$1:$2}
		;;
	    *)  echo "Usage: strcat var string [a:b]"
		return 2
		;;
	esac
	eval "$_VAR=\${$_VAR}\$_STRING"
    }

    strcpy ()		# var=string
    {
	local _VAR=$1 _STRING=$2 _a _b

	case $#.$3 in
	    2.) ;;
	    3.*:*) _a=${3%:*} _b=${3#*:}
		set -- `python_to_shell_range "$_a" "$_b" ${#_STRING}`
		_STRING=${_STRING:$1:$2}
		;;
	    *)  echo "Usage: strcpy var string [a:b]"
		return 2
		;;
	esac
	eval "$_VAR=\$_STRING"
    }
where 'var' is the name of variable you want to use to store the result. The above example, then, becomes
    x=a
    strcpy $x abc		# a=abc
    strcat $x 123		# a+=123

strlen()

In C, strlen(3) gives you the size of a string. In the shell, you would use parameter expansion (i.e., ${#var}):

    a=abc123
    echo ${#a}			# 6
Here is a shell version of C function strlen(3):
    strlen ()		# echo ${#string} ...
    {
	for i in "$@"; do
	    echo ${#i}
	done
    }
which has the additional ability of accepting multiple strings, e.g.
    strlen abc123 0123456789		# 6 10

strcmp()

To compare two strings for equality, you use strcmp(3) in C. In shell, you would do something like

    [ $a = abc123 ]
Here is a shell version of C function strcmp(3):
    strcmp ()		# string == string
    {
	local _STRING1=$1 _STRING2=$2 _a _b
      
	case $#.$3 in
	    2.) ;;
	    3.*:*) _a=${3%:*} _b=${3#*:}
		set -- `python_to_shell_range "$_a" "$_b" ${#_STRING1}`
		_STRING1=${_STRING1:$1:$2}
		set -- `python_to_shell_range "$_a" "$_b" ${#_STRING2}`
		_STRING2=${_STRING2:$1:$2}
		;;
	    *)  echo "Usage: strcmp string1 string2 [a:b]"
		return 2
		;;
	esac
	[ "$_STRING1" == "$_STRING2" ]
    }
so that the above example becomes
    strcmp $a abc123

Python-style [a:b] substring

Extracting substrings is another common operation. In the shell, you would use parameter expansion (i.e., ${var:a:n}), where 'a' is starting index and 'n' is the number of characters to extract. So,

    b=0123456789
    echo ${b:0:3} ${b: -3} ${b:1:${#b}-2}
will print the first 3 chars, the last 3 chars, and all chars except the first and the last, respectively.

The main problem with this syntax is that 'n' is a relative number starting at index 'a'. Usually, absolute index is more convenient, not only because it's more natural, but also because that's the way it is in C. Python has syntax var[a:b], where 'a' and 'b' are indexes which can be positive, negative, or omitted. Although it's roughly equivalent to ${var:a:b-a} in shell, missing 'a' and 'b' means the beginning and the end of string, and negative index means offset from the end of string.

The above shell functions strcat(), strcpy(), and strcmp() already support Python-style [a:b] format, provided you source an internal function.

    # string[a:b] --> ${string:a:n}
    #
    # Convert Python-style string[a:b] range into Shell-style ${string:a:n} range,
    # where
    #	0 <= a <= b <= size  and  a + n = b
    #
    python_to_shell_range ()
    {
	local -i size=$3
	local -i b=${2:-$size}
	local -i a=${1:-0}

	if [ $# -ne 3 ]; then
	    echo "Usage: python_to_shell_range a b size"
	    return 2
	fi

	[[ a -lt 0 ]] && a=$((a+size))
	[[ a -lt 0 ]] && a=0
	[[ a -gt size ]] && a=$size

	[[ b -lt 0 ]] && b=$((b+size))
	[[ b -lt 0 ]] && b=0
	[[ b -gt size ]] && b=$size
	[[ b -lt a ]] && b=$a

	echo $a $((b-a))
    }
to convert Python range to shell range. It's not user-serviceable, but you can try it out:
    python_to_shell_range '' 3 10		# 0 3
    python_to_shell_range -3 '' 10		# 7 3
    python_to_shell_range 1 -1 10		# 1 8
Now, you can specify a substring for strcat(), strcpy(), and strcmp() using Python-style [a:b] range as the third parameter, like this:
    b=0123456789
    strcpy x $b :3		# x=012
    strcpy y $b -3:		# y=789
    strcpy z $b 1:-1		# z=12345678
    echo $x $y $z

Chaining of tests

strcmp() tests two strings for equality. When there is a chain of 2 or more binary tests, like 'a < c > b' or '1 -lt 3 -gt 2', you have to break it up and test each pair:

    [[ a < c ]] && [[ c > b ]]
    [ 1 -lt 3 ] && [ 3 -gt 2 ]
This breaks up the flow of your code, not to mention being error-prone. Here is a shell function which enables you to simply write down the chains on command-line:
    testchain ()		# string OP string OP string ...
    {
	if [ $# -lt 3 ]; then
	    echo "Usage: testchain string OP string [OP string ...]"
	    return 2
	fi
	while [ $# -ge 3 ]; do
	    test "$1" "$2" "$3" || return 1
	    shift 2
	done
    }
where 'OP' is any binary operator accepted by test command. You use it much like test command:
    testchain a '<' c '>' b
    testchain 1 -lt 3 -gt 2

Summary

The source code for the 6 shell functions listed in this article is also available from string.sh. To use it, just source it,
    . string.sh
In the next article, we'll see how strcat(), strcpy(), strlen(), and strcmp() shell functions can be written in C and compiled as builtin commands. And that will be the first introduction to my patched Bash shell. :-)

 

Posted by '김용환'
,

이 글은 메일의 구조이므로 처음부터 뒤로 해서 봐야 합니다.

 

 

 

 

 

 

아파치의 rotatelog 는 과거에서 미래로 시간 정보(date)가 바뀌면 파일이 바뀌는데, 미래에서 과거로 가게되면, 파일이 안바뀌는 문제가 있었습니다..

 

 

오늘 약간 제가 시간이 되어 확인해 보니...

제가 cronolog를 이용하니, 밑의 메일에서 보이는 고질적인(?) 문제가 그대로 재현되어 사용에 대한 어려움이 있습니다.

 

그래서, 차라리 rotatelog를 수정하는 것이 좋을 듯 해서 소스를 수정하였습니다.

이 소스는 관리자에게 주면 소스 컴파일해서 설치하면 자연스럽게 사용할 수 있습니다.

 

테스트는 다음과 같이 하였습니다.

시간을 변경하였습니다.   [현재 -> 미래 -> 현재]

테스트 서버는 e65002서버입니다.

 

[e65002:/root]# /usr/bin/rdate -s time.naver.com
[e65002:/root]# date 01161111
2008. 01. 16. (
¼ö) 11:11:00 KST
[e65002:/root]# /usr/bin/rdate -s time.naver.com

 

[e65002 /home/www/src/httpd-2.0.59/support]# ./rotatelogs aaa-%y%m%d 86400
today is 1 15
today is 1 15

<시간을 변경함 15->16>
16th changed
16th changed 
n
n
n

<시간을 변경함 16->15>
today is 1 15
today is 1 15

 

 

결과 파일

[e65002 /home/www/src/httpd-2.0.59/support]# cat aaa-080115
today is 1 15
today is 1 15
today is 1 15
today is 1 15
[e65002 /home/www/src/httpd-2.0.59/support]# cat aaa-080116
16th changed
16th changed
n
n
n

  


원인은 시간정보와 관련이 있었습니다.

 

소스에서는 now, start, end (이름은 그냥 편하게 축약했습니다.)라는 변수를 사용합니다.

 

파일을 write할때마다 end 변수에 시간정보를 저장합니다.

end변수와 현재 시간정보를 비교합니다.

 

Now(현재 시간정보) end(과거에 저장되었던 시간정보)와 비교하여 만약 크면,, 파일을 생성하게 됩니다.

 

과거 (11 20) -> 현재 (11 23)

Now             11 20             11.23

End              11.20                   11.20

ð  파일 생성

 

미래 (11 29) -> 현재 (11 23)

Now             11 29             11.23

End              11.29                   11.29

ð  파일 생성하지 않음

 

개발 저자는 과거정보에서 미래로 가는 시점에만 체크하도록 되어 있고, 미래에서 과거로 가는 경우는 체크를 안해놨네요..

 

개인적으로 심심할 때, 수정이 가능한지 살펴보았겠네요.

 

 Cronlog는 테스트를 해보죠..^^

 ========================================

 

 

 

 

시나리오1

 

 실행 중간에 시간이 과거로 갔다가 현재로 돌아옴

 

실행

1) rotatelogs lcs_access_log.%Y%m%d%H 3600 +540

2) date 112001002007

1, 2,3, 4까지 입력

3) /usr/bin/rdate -s time.naver.com

1111, 2222입력

 

-rw-r--r--   1 www  www     16 11¿ù 20 01:00 lcs_access_log.2007112001

-rw-r--r--   1 www  www     19 11¿ù 23 11:49 lcs_access_log.2007112311

 

결과

원하는 결과 도출

[e65004 /home/www/src/httpd-2.0.59/support]# cat lcs_access_log.2007112001

1

2

3

4

[e65004 /home/www/src/httpd-2.0.59/support]# cat lcs_access_log.2007112311

1111

2222

ð  원하는 결과 나옴

 

 

 

시나리오2

실행 전부터 시간이 예전시간, 현재로 돌아옴

 

 

-rw-r--r--   1 www  www      8 11¿ù 20 01:00 lcs_access_log.2007112001

-rw-r--r--   1 www  www     10 11¿ù 23 11:53 lcs_access_log.2007112311

결과

원하는 결과 도출

[e65004 /home/www/src/httpd-2.0.59/support]# cat lcs_access_log.2007112001

1

2

3

4

[e65004 /home/www/src/httpd-2.0.59/support]# cat lcs_access_log.2007112311

1111

2222

ð  원하는 결과 나옴

 

 

시나리오3

실행 전부터 시간이 미래시간, 현재로 돌아옴

 

[e65004 /home/www/src/httpd-2.0.59/support]# cat lcs_access_log.2007112901

1

2

3

4

5

11111

2222

3333

 

ð  문제 발생

 

진짜 문제 있었습니다. 이 부분을 집중적으로 봐볼께요..

 

 

 -----------------------------------------

 

 

현재 상황으로는 아파치의 rotatelog는 현재 시간에 너무 밀접한 관계를 가지니까. 시간 셋팅에 대한 CRON job이 제대로 ㅣ되어 되어 있는지 확인을 해봤으면 좋겠습니다.

 

Logh-g001 서버 의 irteam 계정을 통해서 본 cron은 다음과 같습니다.

 

다른 서버의 경우는 root www에 아래와 같은 cron job이 있습니다.
이것이 제대로 셋팅되어 있는지 root 관리자에게 함 물어봐주세요..^^

13 * * * * /usr/sbin/ntpdate -s time.google.com

 

 

 

================================

 

약속한 대로 오늘 내로 파악했습니다. 아파치 메소드가 많아서 의미 파악하는데 시간이 조금 소요되었습니다.

 

Rotatelog rotatelog.c 라는 파일이구요. Lucy 어느 서버에나 다음에서 보실 수 있습니다.

 

/home/www/src/httpd-2.0.59/support]# cat rotatelogs.c

 

실제 아파치 httpd.conf 소스

/home1/irteam/google/apache/bin/rotatelogs /home1/irteam/googleapache/logs/lcs_access_log.%Y%m%d%H 3600 +540

 

동작원리는 다음과 같습니다.

 

무한대 {

먼저 입력을 받는다.

현재시간 정보(시스템)를 얻어와서 “lcs_access_log.%Y%m%d%H”파일를 있는지 확인하고, 없으면 생성한다. 파일이 있으면 append한다.

해당 파일을 연다. 입력된 값을 저장한다.

파일을 close한다.

}

아시겠지만, 3600 rolling하는 시간입니다. +540 utc_offset입니다. 모두 파일이름과 관련된 부분에만 관련하고 있습니다.

 

시간 정보를 얻어오는 부분은 다음과 같습니다.

apr_time_now()함수입니다.

 

아파치 2 apr 1.2.;11을 쓰고 있지요.

Apache Portable Runtime (APR) version 1.2.11

 

/* NB NB NB NB This returns GMT!!!!!!!!!! */

APR_DECLARE(apr_time_t) apr_time_now(void)

{

    struct timeval tv;

    gettimeofday(&tv, NULL);

    return tv.tv_sec * APR_USEC_PER_SEC + tv.tv_usec;

}

 

NB 뜻은 nota bene의 약자입니다. 구글링을 해보니.. Nota Bene is a Latin phrase meaning "Note Well," 이렇게 나오는군요.

중요한 것은 그게 아니고…

 

Gettimeofday 라는 함수입니다. 결국 커널로부터 시간정보를 얻어오네요.

http://www.joinc.co.kr/modules/moniwiki/wiki.php/man/2/gettimeofday

http://man.cx/gettimeofday(2)/ko

 

gettimeofday라는 함수가 첫번째 파라미터에 null을 넣지 않고, 두번째 파라미터에 null을 넣었습니다.

이것은 계속 변할 수 있는 값을 의미합니다.

 

이정도면 되겠는지요??

 

시스템 시간이 바뀌면 rotatelog에서 로깅하는 파일 시간도 바뀝니다…^^

 

만약 시스템 시간에 무관하게 찍을 려면, rotatelog를 수정해야 할 것 같네요. Apr apr_time_now() 함수를 다른 것으로 대체해야 할 듯으로 보입니다.

 

'unix and linux' 카테고리의 다른 글

bash 스트링 조작하기  (0) 2008.01.18
고급 Bash 스크립팅 가이드  (0) 2008.01.18
getopt() 함수  (0) 2008.01.16
ssldump 설치하기  (0) 2008.01.04
모든 파일 안의 문자열 치환하기  (0) 2007.12.31
Posted by '김용환'
,

getopt() 함수

unix and linux 2008. 1. 16. 08:12

출처 : vega.icu.ac.kr/~kimkk

 

 

getopt( )


본 문서는 명령행에서 옵션및 옵션 아규먼트를 추출하는데 사용가능한 getopts 명령어, 본쉘(Bourn Shell) 내장 명령어로서의 getopts, C라이브러리 함수로 제공되는 getopt() 함수에 대하여 설명한다.


0.2 작성자

한국정보통신대학원대학교 소프트웨어시스템연구실 김홍숙

Email : kimkk@icu.ac.kr

WWW   : vega.icu.ac.kr/~kimkk


0.3 참조 문서

Solaris의 man pages ( getopts(1) for user command, getopt(3C) for C library function)


0.4 문서 변경사항

2000.11.07 : 최초 작성

--------------------------------------------------------------------

1. 사용자 명령어로써의 getopts

getopts 유틸리티는 파라메터들의 리스트에서 옵션(options)과 옵션-파라메터(option-parameter)를 추출하는데 사용한다.


1.1 사용법

getopts의 사용 방법은 다음과 같다.

/usr/bin/getopts optstring name  [ arg ...  ]


    optstring : 옵션으로 사용될 문자들로 구성된 문자열

    name : getopt가 옵션 분석과정에서 분석된 옵션 문자열을 저자하는 쉘 변수

    arg  : 쉘 스크립트에 전달되는 positional parameter대신 분석하고자 하는

           문자열

1.2 용어 정의

다음과 같은 예에서


$cmd - a - b - o "xxx z yy" -- filename


옵션 문자(option character)는 'o', 'b', 'a'이고 'o'의 경우 옵션 아규먼트(option argument)로 "xxx, z, yy"를 가지는 옵션 문자이다. '--'는 옵션의 끝은 나타내는 특수 옵션이다.


1.2 getopts의 동작 과정

getopts가 호출될 때마다, getopts는 쉘 변수 $name에 다음 옵션 문자를 저장하고, 쉘 변수 $OPTIND에 처리하여야 할 다음 아규먼트에 대한 인덱스를 저장한다. 쉘이 호출 될 때 마다, $OPTIND는 1로 초기화된다.


옵션에서 옵션-아규먼트(option-argument)가 필요한 경우, getopts는 옵션-아규먼트를 쉘 변수 $OPTARG에 저장한다. 분석과정 중에 옵션 아규먼트를 필요로 하는 옵션문자가 없거나, 옵션-아규먼트를 필요로 하는 옵션문자가 있지만 이에 대한 에옵션 아규먼트가 없는 경우에 $OPTARG는 unset된다.


optionstring 오퍼랜드에 포함되지 있지 않은 옵션 문자가 옵션 문자 위치에 있는 경우 name으로 지정된 쉘 변수는 물음표 '?'로 설정된다. 이 경우, optstring의 첫 문자가 콜론 ':'이라면, 쉘 변수 $OPTARG는 발견된 옵션 문자로 설정되며, 표준 에러 출력(stderr)에는 아무 것도 출력되지 않는다. 그 이외의 경우에 쉘 변수 $OPTARG는 unset되고 표준 에러 출력으로 diagonostic message가 출력된다. 이러한 상황은 호출하는 애플리케이션에 아규먼트가 주어지는진 과정에서 탐지된 에러로 볼 수는 있지만, getopts 처리과정에서의 에러는 아니다.


옵션 아규먼트가 없는 경우

l       optstring의 첫번째 문자가 콜론 ':'인 경우, name으로 지정된 쉘 변수는 콜론 ':'문자    로 설정되고, 쉘 변수 OPTARG는 발견된 옵션 문자로 설정된다.

l       optstring의 첫번째 문자가 콜론 ':'이 아닌 경우에는 name으로 지정된 쉘 변수는 물음표 ?'로 설정되고, 쉘 변수 OPTARG는 unset되면서 표준 에러 출력으로 diagonostic message가 출력된다. 이러한 상황은 호출하는 애플려케이션에 아규먼트가 주어지는 과정에서 탐지되는 에러로 볼 수는 있지만, getopts 처리과정에서의 에러는 아니다. diagonostic messge가 위에서 기술한 것처럼 출력되기는 하지만 exit status는 0으로 설정된다.


옵션의 마지막에 도달한 경우, getopts는 1이상의 리턴값을 가지고 exit한다. 쉘 변수 OPTIND 값은 옵션-아규먼트가 아닌 첫번째 옵션에 대한 인덱스로 설정된다. 최초의 -- 아규먼트 이전에 다른 non-option-argument가 없는 경우에 -- 아규먼트는 옵션-아규먼트로 간주된다. 최초의 --아규먼트 이전에 다른 non-option-argument가 있고 다른 non-option-argument가 없는 경우에는 최초의 -- 아규먼트는 $#+1의 값을 가지는 아규먼트로 간주되며 name변수의 값은 물음표 '?'로 설정된다.  다음의 조건중 하나를 만족하는 경우 옵션의 끝이 된다.

         . 스페셜 옵션 --

         . -로 시작하지 안는 아규먼트를 발경한 경우

         . 에러가 발생한 경우


1.3 getopt와 관련한 쉘 환경 변수에 따른 유의사항

l       쉘 변수 OPTIND와 OPTARG는 getopts를 호출한 caller에 로컬이며 기본적으로 export되지 않는다.

l       쉘변수 $name, $OPTIND, $OPTARG는 현재 쉘의 실행 환경에 영향을 미친다.

l       애플리케이션에서 $OPTIND의 값을 1로 설정한 경우, 새로운 파라메터 셋( 현재 positional parameter 또는 새로운 arg값)이 사용될 수도 있다. 단일 쉘에서 다음과 같이 getopts를 여러번 호출할 경우에 결과는 예측할 수 없다.

-       모든 getopts 호출에서 동일하지 않은 파라메터 (positional paramet 또는 arg 아규먼트)를 사용하는 경우

-       1이 아닌 값으로 OPTIND값을 변경하여 사용하는 경우


2. 본쉘(Bourne shell)의 내장 명령어로써의 getopts

getopts는 본쉘(Bourne shell)의 내장 명령어로써 positional parameter $1 ~ $#을 파싱하고 유효한 옵션인지 검사한다. 본 쉘에 내장 명령어로써의 getopts는 명령 구문 표준(command syntax standard) 의 적용가능한 규칙을 지원하며, getopt 명령어를 대신하여 사용되어야 한다. 명령 구문 표준에 대한 내용은 intro(1)을 참조한다.


2.1 getopts 본쉘 내장 명령어 사용법

본 쉘 내장 명령어인 getopts는 사용자 명령어인 getopts와 사용법이 동일하다.

getopts optstring name  [ arg ...  ]


2.1.1  optstring

getopts를 호출하는 유틸리티가 인식할 수 있는 옵션 문자들을 포함하고 있는 문자열. 문자뒤에 콜론 ':'이 오면, 해당 옵션은 옵션 아규먼트를 가지며 이 옵션 아규먼트는 별도의 아규먼트로 제공되야 한다. 애플리케이션은 하나의 옵션 문자와 이 옵션 문자의 아규먼트를 별도의 아규먼트로 명시하여야 하지만, getopts는 애플리케이션에서 별도의 아규먼트로 옵션 아규먼트를 지정하는 것과는 상관없이 옵션 아규먼트를 필요로 하는 옵션 문자뒤에 오는 문자들을 옵션 아규먼트로 해석해 버린다.

getopts 호출시에 옵션 아규먼트가 별로의 아규먼트로 제공되지 않는다면 명시적인 null 옵션 아규먼트를 구분할 피요는 없다. getopt(3)을 참조바람. 물음표 '?'와 콜론 ':'은 애플리케이션에서 옵션 구분 문자로 사용할 수 없다. 또한 숫자나 영문자가 아닌 옵션 문자를 사용할 경우의 실행 결과는 예측할 수 없다. 옵션 아규먼트가 별도의 아규먼트로 제공되지 않는 경우, 쉘 변수 $OPTARG의 값은 옵션문자와 -로 없어지게 된다. 옵션 문자가 없거나 옵션 아규먼트가 생략된 경우에 getopts의 동작은 optstring 의 최초 문자에 의해 결정된다.


2.1.2 name

파싱과정에서 옵션 문자를 저장하기 위하여 사용되는 쉘 변수의 이름


2.1.3 arg

getopts는 기본적으로 쉘 프로시져 호출시에 전달되는 positional parameter를 파싱한다. 별도의 아규먼트 arg가 주어진 경우에는 postional parameter대신에 arg로 주어진 문자열을 파싱한다.


2.2  getopts의 동작 과정

getopts는 호출될때 마다, 쉘 변수 $name에 다음 옵션을 저장하고 다음 처리할 옵션에 대한 인덱스를 쉘 변수 $OPTIND에 저장한다. 쉘 또는 쉘 스크립트가 호출될 때마다, 쉘 변수 $OPTIND의 값은 1로 초기화된다.


옵션이 옵션-아규먼트를 필요로 할 경우, getopts는 옵션-아규먼트를 쉘 변수 $OPTARG에 저장한다.


올바르지 않은 옵션을 만나는 경우에는 물음표 '?'가 쉘 변수 $name에 저장된다.


옵션의 끝에 도달한 경우, getopts는 0이 아닌 exit status로 종료한다. 특수 옵션 --가 옵션을 끝을 나타내기 위하여 사용될 수 있다.


기본적으로, getopts는 positional parameter를 파싱한다. 만일  별도의  아규먼트 arg가 getopts에 주어진 경우, getopts는 positional parameter대신에 별도로 주어진 아규먼트 arg를 파싱한다.


/usr/lib/getoptcvt는 filename내의 쉘 스크립트를 읽어들여, 이를 getopt대신에 getopts를 사용하도록 변환한 후 결과를 표준 출력에 출력한다.


모든 새로 작성되는 명령어는 intro(1)에서 기술된 명령 구문 표준(command syntax standard)을 준수하기 위하여 getopts또는 getopt를 사용하여 positional parameters를 파싱하고 해당 명령어에 유효한 옵션인지를 검사하여야 한다.


getopts수행후에는 다음의 종료값이 리턴된다.


     0         optstring에 의해 지정되거나 지정되지 않은 옵션이 발견됨


     >0        옵션의 끝 또는 에러가 발생


2.3 예제

2.3.1 예제 1

다음의 코드는 optstring은 "abo:"으로 하고 c를 다음 옵션을 저장하기 위한 쉘 변수로 하여 프로그래밍한 예이다.


요약 설명

"abo:"   : 옵션 문자로 사용될 문자들을 지정한 optstring으로

           -a, -b, -o의 옵션 문자가 사용될수 있으며 -o옵션은 옵션 아규먼트를 가진다.

$c       : 다음 옵션을 위한 사용자 쉘 변수

$OPTARG  : 옵션이 옵션-아규먼트를 필요로 하는 경우 옵션-아규먼트가 저장되는 쉘 내장 변수



      예제 코드)

      while getopts abo: c

      do

           case $c in

              a | b)   FLAG=$c;;

              o)       OARG=$OPTARG;;

              \?)      echo $USAGE

                       exit 2;;

           esac

     done

     shift `expr $OPTIND - 1`



위의 코드는 다음의 모든 명령행을 동등한 것으로 취급한다.


     cmd -a -b -o "xxx z yy" filename

     cmd -a -b -o "xxx z yy" -- filename

     cmd -ab -o xxx,z,yy filename

     cmd -ab -o "xxx z yy" filename

     cmd -o xxx,z,yy -b -a filename


2.3.1 예제 2

다음의 쉘 스크립트는 입력 아규먼트(positional parameter)를 파싱하고 출력하는 예이다.


     aflag=

     bflag=

     while getopts ab: name

     do

          case $name in

          a)      aflag=1;;

          b)      bflag=1

                  bval="$OPTARG";;

          ?)     printf "Usage: %s: [-a] [-b value] args\n"  $0

                 exit 2;;

          esac

     done

     if [ ! -z "$aflag" ]; then

        printf "Option -a specified\n"

     fi

     if [ ! -z "$bflag" ]; then

          printf 'Option -b "%s" specified\n' "$bval"

     fi

     shift $(($OPTIND - 1))

     printf "Remaining arguments are: %s\n" "$*"


getopts는 optstring에 포함되지 않은 옵션 문자를 만나는 경우 표준 에러 출력으로 에러 메시지를 출력한다.


2.3 완화된 명령 구문 규칙에 따른 유의사항

다음과 같은 완화된 명령 구문 규칙( intro(1)참조)이 현재의 구현에서 허용되기는 하지만, 다음 버젼에서는 지원되지 않을 수도 있기 때문에 사용하지 않아야 한다. 위의 예에서 a와 b는 옵션이고 옵션 o는 옵션 아규먼트를 필요로 하는 아규먼트이다.


다음의 예는 옵션 아규먼트를 가지는 옵션은 다른 옵션들과 묶여져서는 안된다는 Rule 5를 위반하고 있다.

     example% cmd - aboxxx filename


다음의 예는 옵션 아규먼트를 가지는 옵션의 다음에는 공백문자가 있어야 한다는 Rule 6를 위반하고 있다.

     example% cmd - ab oxxx filename

     example% cmd - ab oxxx filename


쉘 변수 OPTIND의 값을 변경하거나 다른 아규먼트 셋을 파싱하는 경우, 결과는 예측할 수 없다.



2.5 서브 쉘 또는 다른 실행환경에서  getopts의 동작시 유의사항

getopts는 현재 쉘의 실행 환경(shell execution environment)에 영향을 주기 때문에, 일반적으로 쉘의 내장 명령어로 제공된다. getopts간 서브쉘에서 호출되거나, 다음과 같이 별도의 유틸리티 실행 환경에서 호출되는 경우

            (getopts abc value "$@")

            nohup getopts ...

            find . - exec getopts ... \;

이를 호출한 부모 쉘의 환경(caller's environment)에는 영향을 줄 수가 없다.


positional parameter가 변할 수는 있지만, 쉘 함수(shell function)는 호출하는 쉘과$OPTIND 쉘 변수를 공유한다는 점에 유의하여야 한다. 일반적으로 getopts를 사용하여 입력 아규먼트를 파싱하고자하는 쉘 함수는 시작시에 $OPTIND의 값을 저장하고 리턴하기 전에 $OPTIND의 값을 시작시 에 저장한 값으로 복구한다. 그러나 쉘 함수를 호출하는 쉘을 위하여 $OPTIND를 바꾸기를 원하는 경우도 있을 수 있다.


3. C 라이브러리 함수 getopt

getopt는 C 라이브러리 함수 getopt()의 형태로도 제공된다. getopt()함수를 C코드에서 사용하기 위해서는 다음과 같이 <stdlib.h> 헤더 파일을 include하여야 한다.

     #include <stdlib.h>


3.1 함수 프로토타입

     int getopt(int argc, char * const *argv,  const  char  *optstring);

     extern char *optarg;

     extern int optind, opterr, optopt;

3.2 함수 설명

getopt() 함수는 char **argv에서 char *optstring내에 있는 문자중 하나와 일치하는 옵션 문자를 리턴한다. getopt()함수는 명령 구문 표준에 있는 모든 규칙을 지원한다. 새로 작성되는 모든 명령어들은 명령 구문 표준을 준수하여야 하므로, 명령행에서 positonal parameter를 분석하고 유효한지를 검사하기 위해서는 사용자 명령어인 getopts,또는 C 라이브러리 함수인 getopt(), getsubopt()를 사용하여야 한다.


char *optstring은 getopt() 함수가 처리하여야할 옵션 문자들을 포함한다. 옵션 문자뒤에 콜론 ':'이 오면, 해당 옵션이 한 개의 옵션 아규먼트 또는 공백 문자로 분리되는 복수개의 옵션 아규먼트를 가지는 것을 나타낸다.


char *optarg는 getopt()함수의 리턴시에 옵션 아규먼트의 시작 위치를 가리키도록 설정된다.


getopt() 함수는 extern int optind에 다음에 처리할 아규먼트에 대한 char **argv내에서의인덱스를 저장한다( char **argv는 의미적으로 char *argv[]와 동등하다). extern int optind

getopt()함수의 최초 호출전에 1로 초기화된다.


모든 옵션이 처리되고 나면( 즉 옵션이 아닌 아규먼트를 만나게 되면), getopt()는 EOF를 리턴한다.

연속되는 두개의 하이픈으로 표시되는 특수 옵션 '--'를 사용하여 옵션의 끝을 나타낼수도 있다.

getopt() 함수가 '--'를 만나는 경우에도 EOF가 리턴된다. 특수 옵션 '--'는 '-'로 시작하는 옵션이 아닌 문자열을 처리하고자 할 때 유용하게 사용할 수 있다.


3.3 리턴값

getopt() 함수가 char *optstring에서 지정되지 않은 옵션 문자를 만나거나 옵션 아규먼트를 가지는 옵션문자뒤에 옵션 아규먼트가 없는 경우에 표준 에러(stderr)에 에러 메시지를 출력하고 "?"를 리턴한다. extern int opterr을 0으로 설정하여 에러 메시지가 출력되지 않도록 할 수도 있다. 에러를 유발시킨 문자는 extern int optopt에 저장된다.


3.4 getopt() 함수 사용에 따른 유의 사항

getopt() 함수를 사용한 C코드가 -lintl로 링크되는 경우에, getopt()가 출력하는 메시지는

LC_message locale category로 지정된 국가 언어로 출력된다. 자세한 내용은 setlocale()

함수를 참조한다.


getopt() 함수는 옵션 아규먼트에 대한 것을 완벽하게 검사하지는 않는다. 예를 들어 옵션 문자열 optstring이 "a:b"이고 char **argv에  "-a -b"가 입력으로 사용된 경우,  getopt() 함수는 "-b"를 "-a"옵션에 대한 옵션 아규먼트로 처리한다.


아래의 예와 같이 옵션과 옵션 아규먼트를 함께 묶에서 사용하는 것은 명령 구문 표준을 위반한다.

cmd -abo filename


위의 예에서 a와 b는 옵션이고 o는 옵션 아규먼트를 필요로하는 옵션이며 filename은 옵션 o에 대한 옵션 아규먼트이다. 현재 버젼의 getopt()에서는 이러한 구문이 허용되기는 하지만, 차기 버전에서 이러한 구문이 지원되지 않을 수도 있으므로 다음과 같은 명령 구문 표준에 맞게 사용하여야 한다.

     cmd -ab -o filename.


3.4 getopt() 함수를 사용한 C 프로그램 예제

다음의 예제 코드는 C 프로그램에서 getopt() 함수를 사용하여 명령행 옵션을 처리하는

과정을 예시한 것으로 옵션 -a, -b와 옵션 아규먼트를 사용하는 -o옵션을 처리하는

코드이다.

     #include <stdlib.h>

     #include <stdio.h>

     main (int argc, char **argv)

     {

        int c;

        extern char *optarg;

        extern int optind;

        int aflg = 0;

        int bflg = 0;

        int errflg = 0;

        char *ofile = NULL;


        while ((c = getopt(argc, argv, "abo:")) != EOF)

           switch (c) {

           case 'a':

              if (bflg)

                 errflg++;

              else

                 aflg++;

              break;

           case 'b':

              if (aflg)

                 errflg++;

              else

                 bflg++;

              break;

           case 'o':

              ofile = optarg;

              (void)printf("ofile = %s\n", ofile);

              break;

           case '?':

              errflg++;

           }

        if (errflg) {

           (void)fprintf(stderr,

              "usage: cmd [-a|-b] [-o <filename>] files...\n");

           exit (2);

            }

            for ( ; optind < argc; optind++)

          (void)printf("%s\n", argv[optind]);    return 0;

     }


4 참고 사항

4.1 리눅스에서의 명령행 옵션 분석 지원 라이브러리

리눅스에서는 명령행 옵션 분석을 위한 getopt외에 별도의 popt 라이브러리를 제공하며 이 라이브러리에서는

다음과 같은 여러가지 함수들을 제공한다. 자세한 내용은 man popt를 사용한 온라인 문서또는 다음의 참고서적에서

확인하기 바란다.

Michael K. Johnson and Erik W. Troan, "Linux Application Development", Addison Wesley Longman, Inc., 1998


#include <popt.h>

poptContext poptGetContext(char * name, int argc, char ** argv,

struct poptOption * options,  int flags);

void poptFreeContext(poptContext con);

void poptResetContext(poptContext con);

int poptGetNextOpt(poptContext con);

char * poptgetoptArg(poptContext con);

char * poptGetArg(poptContext con);

char * poptPeekArg(poptContext con);

char ** poptGetArgs(poptContext con);

const char * poptStrerror(const int error);

char * poptBadOption(poptContext con, int flags);

int poptReadDefaultConfig(poptContext con, int flags);

int poptReadConfigFile(poptContext con, char * fn);

int poptAddAlias(poptContext con, struct poptAlias alias, int flags);

int poptParseArgvString(char * s, int *  argcPtr, char *** argvPtr);

int poptStuffArgs(poptContext con, char ** argv);



4.2 Perl에서의 지원

Perl에서도 getopts 또는 getopt 모듈은 지원한다. 자세한 내용은 man perltoc또는 man perlfunc또는 man perlopentut를 통하여 온라인 문서로 확인할 수 있다.


4.3 본쉘외의 다른 쉘에서의 getopts 지원

zsh, ksh에서도 getopts를 지원한다. 상세한 내용은  각 쉘의 man page를 참조한다.

 

'unix and linux' 카테고리의 다른 글

고급 Bash 스크립팅 가이드  (0) 2008.01.18
rotatelog.c 버그 수정해놓기  (0) 2008.01.16
ssldump 설치하기  (0) 2008.01.04
모든 파일 안의 문자열 치환하기  (0) 2007.12.31
특수 파일 삭제하기  (0) 2007.12.31
Posted by '김용환'
,

 

우선 java단에서 막고 있는지를 먼저 확인하라.

에러가 날때, oracle db 연결할때 setCommitAction 이라는 메소드부근에서 나는 것을 확인할 것이다.

 

이는 여러가지 이유가 있을 텐데.

좀 쉽게 찾았다.

 

해당 서버가 연결하는 데, 특정서버로 httpClient 콜을 하고 리턴 값을 받아오고 있음을 발견했다. 해당 서버로 가보니, access를 막고 있는 것이 아닌가

확인해보니, 톰캣의 filter를 이용하여 특정 서버에서 오는 것만 체크하고 있는 것이 아닌가? ip를 넣고 확인해 보니, 완전 문제 해결~ 헐~

 

 

 

 

이래도 안되면 다음을 참조하라

 

소켓에서 읽을 데이터가 없습니다. 에러메세지

http://www.javaservice.net/~java/bbs/read.cgi?b=jdbc&c=r_p&m=devtip&n=1083205594&s=t
WAS 4.0/5.0/5.1 JDBC Datasource 파라메터 의미
http://www.javaservice.net/~java/bbs/read.cgi?m=appserver&b=was&c=r_p&n=1080623459
Re: TCP/IP ESTABLISHED & Connection Timeout 
http://www.javaservice.net/~java/bbs/read.cgi?m=unix&b=unix&c=r_p&n=1005195947
Re: DB Connection Pool: Orphan and Idle Timeout 
http://www.javaservice.net/~java/bbs/read.cgi?m=devtip&b=servlet&c=r_p&n=1005294960#1005294960

'Trend' 카테고리의 다른 글

Common Development and Distribution License (CDDL)  (0) 2008.01.21
리뷰 고고싱 게임?!!!  (0) 2008.01.21
RewriteRule 만약 Request URI에 %가 있다면, 다음을 사용하자  (0) 2008.01.10
리딩업  (0) 2007.11.30
친절한  (0) 2007.11.27
Posted by '김용환'
,

ie7pro

Tool 2008. 1. 14. 10:13

플래쉬 광고 없애준다는 툴이란다.

 

ie7pro 설명

 

http://tais9.tistory.com/440

Posted by '김용환'
,

RewirteRule 팁

: Request URI에 %, 나 $ 와 같은 특수 문자가 있으면, 다음을 설정해라

 

RewriteRule     ^/launcher/App/landing.aspx(.*) /Launcher/App/Landing.aspx$1 [R,NE]

 

출처 :

http://rosebud.stanford.edu/manual/mod/mod_rewrite.html

 

 

'noescape|NE' (no URI escaping of output)
This flag keeps mod_rewrite from applying the usual URI escaping rules to the result of a rewrite. Ordinarily, special characters (such as '%', '$', ';', and so on) will be escaped into their hexcode equivalents ('%25', '%24', and '%3B', respectively); this flag prevents this from being done. This allows percent symbols to appear in the output, as in

RewriteRule /foo/(.*) /bar?arg=P1\%3d$1 [R,NE]

 

 

'Trend' 카테고리의 다른 글

리뷰 고고싱 게임?!!!  (0) 2008.01.21
소켓에서 읽을 데이터가 없습니다 라고 에러가 날때  (0) 2008.01.14
리딩업  (0) 2007.11.30
친절한  (0) 2007.11.27
울프팀 이야기  (0) 2007.10.24
Posted by '김용환'
,

 

pcap을 다운받는다.
(위치 : http://www.tcpdump.org/#latest)
wget http://www.tcpdump.org/release/libpcap-0.9.8.tar.gz

tar zxvf lib*
./configure
./make
./make install

 ln -s /usr/include/pcap-bpf.h /usr/local/include/net/bpf.h
(ssldump 설치시 영향있음)


------------------

ssldump를 다운받는다. (위치 :  http://www.rtfm.com/ssldump/)
wget http://www.rtfm.com/ssldump/ssldump-0.9b3.tar.gz
tar zxvf ssl*
./configure
make
make install

 

 

 

ssldump home page

ssldump is an SSLv3/TLS network protocol analyzer. It identifies TCP connections on the chosen network interface and attempts to interpret them as SSLv3/TLS traffic. When it identifies SSLv3/TLS traffic, it decodes the records and displays them in a textual form to stdout. If provided with the appropriate keying material, it will also decrypt the connections and display the application data traffic.

 

ssldump 0.9b3

The current version is 0.9b3

ssldump 0.9b3 contains a number of fixes and enhancements over 0.9b2, including.

  • Security fix: some potential over and underflows
  • Added support for VLANs.
  • Added -P flag to disable promiscuous mode. Fixed bugs in the TCP reassembly code.
  • A lot of bug fixes.

See the ChangeLog for a more complete list of changes.

To report bugs, please click here.

 

Security Note

version 0.9b3 fixes two security problems with protocol decoding. If you run ssldump in an environment where an attacker might be able to send you network packets, you should upgrade immediately.  

Dependencies

ssldump depends on the libpcap packet capture library. Some systems (e.g. FreeBSD) now have libpcap as part of their standard install. On other systems, you will need to install it. You can obtain the distribution from http://www.tcpdump.org.

If linked with OpenSSL, ssldump can display certificates in decoded form and decrypt traffic (provided that it has the appropriate keying material). Again, OpenSSL may be installed on your system. Otherwise you can obtain it from http://www.openssl.org

 

Downloading

The distribution is available here

The CVS tree, containing the latest source (probably unstable) is available here, courtesy of

 

Mailing List

Discussion of ssldump takes place on the ssldump mailing list.
Subscription is handled by Majordomo. to subscribe send mail to majordomo@rtfm.com with the text "subscribe" (without the quotes) in the message body.
To send mail to the list, send it to ssldump-users@rtfm.com. The archives are hosted by Kevin Fu here.

 

Compatibility

ssldump is known to work on FreeBSD, Linux, Solaris, and HP/UX but should work on any platform with pcap. If you encounter problems, please report them. The Windows port is new as of this release and so it has received only modest testing.

 

Documentation

Some documentation can be found here.

 

Sample Output

Here's an example trace generated by ssldump.

New TCP connection #3: localhost(3638) <-> localhost(4433)
3 1  0.0738 (0.0738)  C>S  Handshake      ClientHello
3 2  0.0743 (0.0004)  S>C  Handshake      ServerHello
3 3  0.0743 (0.0000)  S>C  Handshake      Certificate
3 4  0.0743 (0.0000)  S>C  Handshake      ServerHelloDone
3 5  0.0866 (0.0123)  C>S  Handshake      ClientKeyExchange
3 6  0.0866 (0.0000)  C>S  ChangeCipherSpec
3 7  0.0866 (0.0000)  C>S  Handshake      Finished
3 8  0.0909 (0.0043)  S>C  ChangeCipherSpec
3 9  0.0909 (0.0000)  S>C  Handshake      Finished
3 10 1.8652 (1.7742)  C>S  application_data
3 11 2.7539 (0.8887)  C>S  application_data
3 12 5.1861 (2.4321)  C>S  Alert          warning          close_notify
3    5.1868 (0.0007)  C>S  TCP FIN
3    5.1893 (0.0024)  S>C  TCP FIN

This example uses the flags for minimal decoding. ssldump has flags to allow decoding of all messages, including printing the application protocol data.

 

PGP Signature.

Here is a PGP signature over the latest version of ssldump.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (FreeBSD)
Comment: For info see http://www.gnupg.org

iD8DBQA9f3tv3n8ERpUIz6cRArxkAJwOde/y39HRzo0aqcQhd1+t62cSwACdH5R9
NJxutYXV724xc4N0O7UT9Y4=
=SHz4
-----END PGP SIGNATURE-----

My key fingerprint is:

465E 8A2B 9258 E9CA CE65  1DC3 DE7F 0446 9508 CFA7

 

Shameless Plug

Extremely detailed coverage of SSL/TLS can be found in

SSL and TLS: Designing and Building Secure Systems
Eric Rescorla
Addison-Wesley, 2001
ISBN 0-201-61598-3

SSL and TLS makes extensive use of ssldump to demonstrate real-life SSL behavior. If you like ssldump and want to learn about SSL, you might consider buying my book.

 

'unix and linux' 카테고리의 다른 글

rotatelog.c 버그 수정해놓기  (0) 2008.01.16
getopt() 함수  (0) 2008.01.16
모든 파일 안의 문자열 치환하기  (0) 2007.12.31
특수 파일 삭제하기  (0) 2007.12.31
so 로딩 에러  (0) 2007.12.31
Posted by '김용환'
,

 

replace php gle -- 'ls'

 

php파일안의 link를 gle로 바꾸고 싶을 떄 사용한다.

 

 

디렉토리안의 확장자를 한꺼번에 바꿀 때는

 

rename html php *.html

'unix and linux' 카테고리의 다른 글

getopt() 함수  (0) 2008.01.16
ssldump 설치하기  (0) 2008.01.04
특수 파일 삭제하기  (0) 2007.12.31
so 로딩 에러  (0) 2007.12.31
vi 팁  (0) 2007.12.31
Posted by '김용환'
,

 

--이나 -등으로 시작되는 파일이름을 삭제하고 싶을때..

 

rm -- --abc.txt 하면 된다.

 

-- 옵션은 옵션이 아무것도 없다라는 의미이다.

'unix and linux' 카테고리의 다른 글

ssldump 설치하기  (0) 2008.01.04
모든 파일 안의 문자열 치환하기  (0) 2007.12.31
so 로딩 에러  (0) 2007.12.31
vi 팁  (0) 2007.12.31
grep 사용  (0) 2007.12.30
Posted by '김용환'
,