Bourne Shell Builtins
.
. filename [arguments]
bash 에서 source 명령과 같은 기능의 명령입니다. sh
에서는 source 명령을 사용하지 못하므로 이 명령을 사용해야 합니다. filename 을 읽어들여 현재 shell 에서 실행하는데 가령 AA.sh 파일내용 중에 . BB.sh
라인이 있다면 해당라인이 위치한 곳에 BB.sh 파일을 읽어들여 실행합니다. child process 가 생성되는 것은 아니고 현재 AA.sh process 에서 실행됩니다.
function 과 동일하게 인수를 줄 수 있으며 BB.sh 에서는 return 명령을 사용할 수 있습니다. 인수를 주지 않을 경우 AA.sh 실행시 사용된 인수가 동일하게 적용됩니다.
filename 에 경로를 지정하지 않으면 $PATH
를 검색하는데 찾지 못하면 오류메시지와 함께 non-zero 를 리턴합니다.
:
:
아무일도 하지 않는 명령입니다. 종료 상태 값으로 항상 0 을 리턴합니다. 실질적으로 true
명령과 동일합니다 ( 예전에는 true 명령이 이 명령의 alias 였습니다. ). 간단한 스크립트 테스트를 할때 true 가 올수있는 자리에 대신 사용하기에 편합니다. 또한 실행 시에 인수부분에서 변수확장, 명령치환, 산술확장이 이루어지므로 디버깅 시에 특정 값을 보기위해 사용할 수도 있습니다. 여러모로 활용성이 있는 명령입니다.
while :; do echo $(( i++ )); sleep 1; done
if :; then :; else :; fi
# dir 변수가 존재하지 않거나 null 값일 경우 '/usr/local' 을 대입
: ${dir:=/usr/local}
break
break [n]
for, while, until 반복구문에서 사용되는 명령입니다. 현재 실행되고 있는 반복을 중단하는 역할을 합니다. 반복구문이 중첩 될수있는데 이때 n
인자를 사용할수 있습니다.
cd
cd [-L|[-P [-e]] [-@]] [dir]
현재 작업중인 디렉토리를 변경합니다. -P
옵션을 주면 심볼릭 링크 디렉토리 구조를 따르지 않고 물리적 디렉토리 구조를 따름니다
continue
continue [n]
for, while, until 반복구문에서 사용되는 명령입니다. continue 명령이 실행되면 현재 반복을 중단하고 다음반복으로 넘어갑니다. 반복구문이 중첩 될수있는데 이때 n
인자를 사용할수 있습니다.
eval
eval [arg ...]
eval 메뉴 참조.
exec
exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
현재 shell process 를 command 로 대체합니다. 프롬프트 상에서와 달리 스크립트 실행시에는 command 를 실행할수 없을경우 exit 됩니다. ( exit 을 방지하기 위해 execfail 옵션을 사용할수 있습니다. )
현재 shell 에 redirection 을 적용시킵니다.
exit
exit [n]
shell 을 exit 합니다. n
은 종료 상태 값이 되며 $?
를 통해 구할수 있습니다. n
값을 설정하지 않으면 이전 명령의 종료 상태 값이 사용됩니다.
export
export [-fn] [name[=value] ...] or export -p
A.sh 스크립트 내에서 B.sh 스크립트를 실행시키면 ( source 가 아님 ) A.sh 은 parent, B.sh 은 child process 가 됩니다. 이때 A.sh 에서 설정한 변수라든지 함수들은 바로 B.sh 에서 사용할 수가 없는데 export 명령을 이용하면 child process 인 B.sh 에서도 사용할 수가 있게 됩니다.
A.sh 에서 export 한 변수를 B.sh 에서 읽고 수정하고 할 수 있지만 변경된 사항이 parent process 인 A.sh 에 적용되지는 않습니다.
함수를 export 할 때는 -f
옵션을 사용합니다.
sh
에서는 변수만 export 할 수 있고 function 은 export 할 수 없습니다.
getopts
getopts optstring name [arg]
명령행에서 사용되는 옵션들을 처리하기 위해 사용되는 명령입니다.
hash
hash [-lr] [-p pathname] [-dt] [name ...]
현재까지 사용된 명령들의 위치와 사용횟수를 기억하고 관리할수 있습니다.
pwd
pwd [-LP]
현재 사용중인 디렉토리를 표시합니다. $PWD
값과 같으며 -P
옵션을 사용할경우 심볼릭 링크 디렉토리 구조를 따르지 않고 물리적 디렉토리 구조를 따라 표시합니다.
readonly
readonly [-aAf] [name[=value] ...] or readonly -p
변수나 함수를 변경할수 없게 합니다. 설정후 변경을 시도하면 오류메시지와 1
을 리턴합니다.
return
return [n]
function 또는 source 한 스트립트 에서 리턴합니다. n
값은 종료 상태 값으로 사용되어 $?
변수를 통해 얻을수 있습니다. return 명령을 사용하지 않을경우 마지막 실행명령의 종료 상태 값이 사용됩니다.
shift
shift [n]
positional parameters 메뉴 참조.
test
test [expr]
Test 메뉴 참조.
trap
trap [-lp] [[arg] signal_spec ...]
trap 메뉴 참조.
umask
umask [-p] [-S] [mode]
User file-creation mode mask 는 파일과 디렉토리를 생성할때 기본적으로 어떤 퍼미션으로 생성할지를 8진수값으로 설정합니다. mask 를 전혀주지 않는다면 ( 000 ) 기본적으로 파일은 666, 디렉토리는 777 로 생성됩니다. 마스크값을 022 로 준다면 파일은 666 에서 각자리수 별로 빼기계산을 하면 644 로 생성이 되고 디렉토리는 755 로 생성이 되게 됩니다. 좀더 자세한 내용은 여기 를 참고하세요.
unset
unset [-f] [-v] [-n] [name ...]
현재 설정돼있는 변수나 함수를 삭제하여 존재하지 않는 상태로 만듭니다. readonly 속성이 있을경우 unset 되지 않습니다. AA=, AA="", AA='' 는 값은 null 이지만 현재 존재하는 ( set 돼있는 ) 변수입니다. unset 을하면 존재하지 않는 상태가 됩니다. [ -v name ]
으로 테스트 해볼수 있습니다. 이때 name 에는 $
를 붙이지 않습니다.
Bash Builtins
[
[ arg... ]
test
명령과 동일한 명령입니다. Test 메뉴를 참조하세요.
alias
alias [-p] [name[=value] ... ]
alias 를 설정하는데 사용합니다. alias 는 기본적으로 non-interactive shell 에서는 사용할수 없습니다.
bg
bg [job_spec ...]
job control 메뉴 참조
bind
bind [-lpsvPSVX] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-x keyseq:shell-command] [keyseq:readline-function or readline-command]
readline 의 설정 파일인 inputrc 에서 할수있는 옵션설정, key binding 을 이 명령을 통해서 동일하게 할 수 있습니다. 사용할 수 있는 함수나 옵션의 목록을 볼수도 있으며 현재 설정 상태도 확인할 수 있습니다.
builtin
builtin [shell-builtin [arg ...]]
우선순위가 높은 alias, function 이름을 피해 builtin 명령을 실행 할때 사용합니다.
caller
caller [expr]
현재 실행중인 함수의 call stack 을 표시합니다. 인수없이 사용하면 라인넘버, 파일이름 (${BASH_LINENO[0]} ${BASH_SOURCE[1]}
) 을 표시하고 숫자를 인수로 주면 라인넘버, 호출함수, 파일이름 (${BASH_LINENO[$i]} ${FUNCNAME[$i+1]} ${BASH_SOURCE[$i+1]}
) 을 표시합니다. stack trace 에 사용할수 있습니다.
#!/bin/bash
die() {
local frame=0
while caller $frame; do
((frame++));
done
echo "$*"
exit 1
}
f1() { die "*** an error occured ***"; }
f2() { f1; }
f3() { f2; }
f3
################ output #################
12 f1 ./callertest.sh
13 f2 ./callertest.sh
14 f3 ./callertest.sh
16 main ./callertest.sh
*** an error occured ***
command
command [-pVv] command [arg ...]
우선순위가 높은 alias, function 이름을 피해 외부명령을 (builtin 명령 포함) 실행 할때 사용합니다.
-v
옵션은 명령이 존재하는지 체크하는데 사용할 수 있습니다.
if command -v python > /dev/null; then ...
compgen
compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]
명령 자동완성에 사용될 단어들를 생성하는데 사용됩니다. 주로 자동완성 함수를 작성할때 COMPREPLY 변수에 값을 채워 넣기 위해 사용합니다. 사용 가능한 옵션은 complete 명령과 거의 동일하며 마지막에 word 인수가 주어지면 word 와 매칭되는 단어들만 선택됩니다.
# -A 옵션에 사용할 수 있는 action 들
$ compgen -A [tab]
alias builtin disabled file helptopic keyword setopt stopped
arrayvar command enabled function hostname running shopt user
binding directory export group job service signal variable
$ compgen -a # 현재 설정되어 있는 aliases
$ compgen -b # builtin commands
$ compgen -c # $PATH 에의해 접근 가능한 시스템 전체 명령 (builtin 명령 포함)
$ compgen -d # 현재 위치에서 디렉토리만 표시
$ compgen -e # export 한 환경변수들
$ compgen -f # 현재 위치에서 모든 파일 표시 (디렉토리, 심볼릭 링크 모두)
$ compgen -g # /etc/group 에 등록된 group
$ compgen -j # background 로 실행중인 모든 job 들
$ compgen -k # shell keywords
$ compgen -s # /etc/services 에 등록된 service
$ compgen -u # /etc/passwd 에 등록된 user
$ compgen -v # 현재 쉘에 설정되어 있는 모든 변수들 (export 안한것 포함)
complete
complete [-abcdefgjksuv] [-pr] [-DE] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]
특정 이름의 자동완성을 등록하고 설정하는 역할을 합니다.
자세한 내용은 Command Completion 메뉴를 참조하세요
compopt
compopt [-o|+o option] [-DE] [name ...]
complete 으로 등록되어 사용 중인 명령 자동완성 에대해서 옵션을 변경할 수 있습니다.
declare
declare [-aAfFgilnrtux] [-p] [name[=value] ...]
변수를 선언하고 속성을 적용합니다. 값을 대입하지 않으면 존재하지 않는 상태 (unset 상태) 로 남습니다. 변수, array 의 현재 속성과 값을 보거나 함수정의를 볼때도 사용합니다. 유효하지 않은 옵션을 사용하거나 값을 대입할때 오류가 나면 종료 상태 값으로 non-zero 를 리턴합니다.
sh 에서는 사용할 수 없습니다. 하지만 함수 내에서 local 은 사용할 수 있습니다.
- Associative array 를 만들때는
declare -A
명령을 사용해야 합니다. - 함수 내에서 사용되면 기본적으로
local
변수로 설정됩니다.-g
옵션으로 global 변수로 설정 할수있습니다. declare -n
을 이용하여 named reference 기능을 이용할수 있습니다.declare -t -f 함수명
을 사용하면 해당 함수에서 DEBUG, RETRUN trap 을 할수 있습니다.
Options:
옵션 | 설명 |
---|---|
-f | 함수 정의를 볼때 사용합니다. 특정 action 을 함수에 적용시킬때 사용합니다. |
-F | 함수 이름만 표시합니다. (디버깅 시에는 line number 와 source file 도 표시합니다.) |
-g | 함수 내에서 declare 는 기본적으로 local 변수를 만듭니다. 하지만 이 옵션을 사용하면 global 변수가 됩니다. |
-p | NAME 의 속성과 값을 볼때 사용합니다. |
속성을 줄때 사용하는 옵션
-
대신에 +
를 사용하면 해당 속성이 off 됩니다.
옵션 | 설명 |
---|---|
-a | NAME 에 indexed arrays 속성을 줍니다. |
-A | NAME 에 associative arrays 속성을 줍니다. |
-i | NAME 에 integer 속성을 줍니다. 값을 대입할때 let 명령과 같이 산술연산을 할 수 있습니다. |
-n | NAME 에 named reference 속성을 줍니다. |
-r | NAME 에 readonly 속성을 줍니다. |
-t | NAME 에 trace 속성을 줍니다. |
-l | NAME 에 값을 대입할때 소문자로 변환합니다. |
-u | NAME 에 값을 대입할때 대문자로 변환합니다. |
-x | NAME 을 export 합니다. |
dirs
dirs [-clpv] [+N] [-N]
pushd, popd 명령과 함께 directory stack 을 다루는데 사용되는 명령으로 현재 stack 내용을 보여줍니다. 0 번은 항상 현재 디렉토리를 나타냅니다.
[ pushd, popd, dirs 로 cd 명령 만들기 ]
disown
disown [-h] [-ar] [jobspec ...]
job control 메뉴 참조
echo
echo [-neE] [arg ...]
기본적으로 escape 문자는 처리하지 않으며 라인 마지막에 newline 을 붙이는데 필요하지 않을경우 -n
옵션을 사용할수 있습니다. -e
옵션을 사용하면 escape 문자가 처리됩니다.
enable
enable [-a] [-dnps] [-f filename] [name ...]
builtin 명령을 disable 또는 enable 시키는데 사용합니다. builtin 명령과 동일한 이름의 외부 명령을 사용하고자 할 때 이 명령으로 builtin 명령을 disable 시킬 수 있습니다.
false
false
항상 종료 상태 값 1
을 리턴하는 명령입니다.
명령이므로 실행이 돼야 종료 값을 얻을 수 있습니다.
$ echo false
false
$ false
$ echo $?
1
fc
fc [-e ename] [-lnr] [first] [last]
command history 에서 지정한 범위의 명령들을 에디터로 불러와 수정하여 스크립트 처럼 한번에 실행시킬수 있습니다.
fc -s [pat=rep] [command]
!
을 이용한 history 확장처럼 명령을 검색하여 실행할수 있습니다.
$ printf "%s\n" "hello\tworld"
hello\tworld
$ fc -s %s=%b printf
printf "%b\n" "hello\tworld"
hello world
fg
fg [job_spec]
job control 메뉴 참조
help
help [-dms] [pattern ...]
Shell builtin 명령의 도움말을 보여줍니다.
history
history [-c] [-d offset] [n] or history -anrw [filename] or history -ps arg [arg...]
command history 메뉴 참조.
jobs
jobs [-lnprs] [jobspec ...] or jobs -x command [args]
job control 메뉴 참조
kill
kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
kill 메뉴 참조.
let
let arg [arg ...]
산술연산 표현식을 위한 명령입니다. 식을 작성할땐 기본적으로 공백없이 붙여야 합니다. 그러나 quote 를 할경우는 공백을 사용할 수 있습니다. 좀 더 자세한 내용은 special expressions 메뉴를 참조하세요
local
local [option] name[=value] ...
local 변수를 설정할때 사용합니다. 그러므로 함수 내에서만 사용할 수 있습니다.declare
명령에서 사용하는 옵션들을 동일하게 사용할 수 있습니다.
$ f1() {
local -i cnt # -i : cnt 변수의 속성을 integer 로 설정
cnt=100
echo $cnt
cnt=cnt+1 # cnt 변수는 integer 속성을 가지고 있으므로
# cnt=$(( cnt + 1 )) 로 하지 않아도 된다.
echo $cnt
}
$ f1
100
101
logout
logout [n]
login shell 일 경우에 logout 합니다. login shell 이 아니면 오류가 발생합니다.
mapfile
mapfile [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]
라인을 array 변수로 읽어들입니다. 변수명을 주지 않으면 MAPFILE 이 사용됩니다. 몇번째 라인부터 얼마나 읽어들일지, 저장되는 array 에는 몇번째 index 부터 입력할지 정할수 있고 callback 명령을 사용할 수도 있습니다.
mapfile -t array < datafile # 이명령은 실질적으로 아래와 같습니다.
while read -r line
do
array[i]="$line"
i=$((i + 1))
done < datafile
-t
읽어들이는 라인에서 newline 을 제거합니다.-s count
몇번째 라인부터 읽어들일지 지정합니다.-n count
몇개의 라인을 읽어들일지 지정합니다. 0 이면 전체 라인을 읽어들입니다.-O origin
array 변수에 몇번째 index 부터 입력할지 지정합니다.-u fd
file descriptor 로부터 라인을 읽어들입니다.
입력되는 array 와 별개로 callback 명령을 사용할 수 있습니다.
-C callback
callback 명령을 지정합니다.-c quantum
몇개의 라인을 읽어들인후 callback 을 호출할지 지정합니다.
$ cat datafile
100 Emma Thomas
200 Alex Jason
300 Madison Randy
400 Sanjay Gupta
500 Nisha Singh
# callback 명령의 $1 에는 index 값이, $2 에는 라인이 전달됩니다.
$ f1() { echo "$1 : $2" ;}
$ mapfile -t -C f1 -c 1 < datafile # -c 1 설정
0 : 100 Emma Thomas
1 : 200 Alex Jason
2 : 300 Madison Randy
3 : 400 Sanjay Gupta
4 : 500 Nisha Singh
$ mapfile -t -C f1 -c 2 < datafile # -c 2 설정
1 : 200 Alex Jason
3 : 400 Sanjay Gupta
$ mapfile -t -C f1 -c 3 < datafile # -c 3 설정
2 : 300 Madison Randy
callback 에서 read 명령을 사용하면 array 에 입력되는 라인이 skip 됩니다.
$ f1() { read -r line ;}
$ mapfile -t -C f1 -c 1 arr < datafile
# 200, 400 라인이 skip 되었다.
$ echo "${arr[0]}"
100 Emma Thomas
$ echo "${arr[1]}"
300 Madison Randy
$ echo "${arr[2]}"
500 Nisha Singh
popd
popd [-n] [+N | -N]
pushd, dirs 명령과 함께 directory stack 을 다루는데 사용되는 명령으로 stack 에서 디렉토리 항목을 삭제합니다.
[ pushd, popd, dirs 로 cd 명령 만들기 ]
printf
printf [-v var] format [arguments]
printf 메뉴 참조
pushd
pushd [-n] [+N | -N | dir]
popd, dirs 명령과 함께 directory stack 을 다루는데 사용되는 명령으로 인수로 사용된 디렉토리를 stack 에 추가하고 cd 합니다.
[ pushd, popd, dirs 로 cd 명령 만들기 ]
read
read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
read 메뉴 참조.
readarray
readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]
mapfile
명령과 동일합니다.
set
set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]
Shell option 을 설정하거나 명령의 인수값을 나타내는 $1
$2
$3
... 변수를 설정하는데 사용합니다. enable 된 옵션은 $SHELLOPTS
변수에 :
로 분리되어 저장되며 $-
변수에는 옵션 flags 가 저장됩니다. 주의할점은 enable 시에는 -
기호를 disable 시에는 +
기호를 사용한다는 것입니다. [ -o 옵션명 ]
으로 현재 설정값을 테스트해볼 수 있습니다.
shopt
shopt [-pqsu] [-o] [optname ...]
Bash option 을 설정하는데 사용합니다. enable 된 옵션은 $BASHOPTS
변수에 :
로 분리되어 저장됩니다. enable 시에는 -s
를 disable 시에는 -u
옵션을 사용하고 -q
옵션을 사용해 값의 설정 여부를 테스트할 수 있습니다.
$ shopt -s nullglob
$ shopt -q nullglob; echo $?
0
$ shopt -u nullglob
$ shopt -q nullglob; echo $?
1
source
source filename [arguments]
. (a period)
명령과 동일합니다.
bash 에서만 사용할수 있고 filename 을 찾을때 $PATH
에서 찾지 못하면 현재 디렉토리 에서도 찾습니다.
$ source <( echo 'AA=100; f1() { echo $AA ;}' )
$ f1
100
$ echo $AA
100
.................................................
# 인수로 11 22 를 전달하면 각각 $1, $2 에 할당됩니다.
$ source <( echo 'echo "XX, $1, $2, ZZ"' ) 11 22
XX, 11, 22, ZZ
suspend
suspend [-f]
job control 메뉴 참조
true
true
항상 종료 상태 값 0
을 리턴하는 명령입니다.
명령이므로 실행이 돼야 종료 값을 얻을 수 있습니다.
$ echo true
true
$ true
$ echo $?
0
type
type [-afptP] name [name ...]
-a
옵션과 함께 사용할경우 alias, keyword, function, builtin, 외부 명령을 모두 구분해서 보여줍니다.-f
검색에서 shell function 은 제외합니다.-p
옵션은 name 이 실행 가능한지 테스트할 때 사용할 수 있습니다. 여기에는 alias, keyword, function, builtin, 외부 명령 모두 포함됩니다. 외부 명령의 경우에는 파일만 존재하면 참이 됩니다. (executable 은 체크하지 않습니다)
# time 은 keyword, ls 는 alias, cd 는 function, history 는 builtin, awk 는 외부 명령
$ type -p time ls cd history awk
/usr/bin/awk
$ echo $?
0
# xxx 가 존재하지 않는다.
$ type -p time ls cd history awk xxx
/usr/bin/awk
$ echo $?
1
-P
옵션은 name 이 외부 파일로 존재하는지 테스트할때 사용할 수 있습니다.
$ type -P ls date sed
/bin/ls
/bin/date
/bin/sed
$ echo $?
0
# 이번 경우는 history 가 builtin 명령이라 외부 파일로 존재하지 않는다.
$ type -P ls date history
/bin/ls
/bin/date
$ echo $?
1
이 옵션은
which
명령과 기능이 비슷한데 다른 점은 which 명령은 파일이 executable 인지도 체크합니다.
-t
name 의 타입을 표시합니다. (alias, keyword, function, builtin, file) 중복되어 존재할 경우 처음 하나만 표시됩니다.
typeset
typeset [-aAfFgilrtux] [-p] name[=value]
declare
명령과 같이 변수의 값이나 속성을 설정하는데 사용합니다. (Obsolete)
ulimit
ulimit [-SHabcdefilmnpqrstuvxT] [limit]
shell 의 리소스 제한을 설정합니다. hard limit (-H) 은 root 유저만 설정할수 있고 soft limit (-S) 은 hard limit 이내에서 일반유저가 설정할수 있습니다. 설정된 값은 해당 shell 과 생성되는 child process 에 적용됩니다. 웹서버나 데이터베이스 서버등을 운영할때 설정값이 너무 낮으면 열린 파일수가 너무 많다거나 스레드를 생성할수 없다거나 하는 리소스관련 오류가 발생할 수 있습니다. 이때는 startup script 파일에서 ulimit 명령을 이용하여 관련된 리소스를 설정하거나 또는 시스템 설정 파일을 수정하여 reboot 후에도 유지되게 합니다.
현재 실행중인 프로세스의 설정 상태는 pid 를 구한후에 cat /proc/$pid/limits
명령으로 알아볼 수 있습니다.
# 다음은 프로세스당 열수있는 최대 파일수를 설정하는 예입니다.
/etc/security/limits.conf
파일에 추가
* soft nofile 65536
* hard nofile 65536
root soft nofile 65536
root hard nofile 65536
----------------------------------------
/etc/pam.d/common-session-noninteractive
/etc/pam.d/common-session
파일에 추가
session required pam_limits.so
unalias
unalias [-a] name [name ...]
설정된 alias 를 삭제 하는데 사용합니다.
wait
wait [-n] [id ...]
job control 메뉴 참조
pushd, popd, dirs 로 cd 명령 만들기
다음은 pushd, popd, dirs 명령을 이용하여 cd 명령을 만드는 예입니다.
기존 cd 명령은 history 기능이 없는데 pushd, popd 명령을 이용하여 history 기능을 구현합니다.cd --
로 history 목록을 볼 수 있고 cd -숫자
로 해당 디렉토리로 이동할 수 있습니다.cd -
는 기존 명령과 동일하게 바로 이전 디렉토리로 이동합니다.
# 아래 내용을 cd.sh 파일에 저장 후 `source cd.sh` 하면 새로운 cd 명령을 사용할 수 있습니다.
# Author : petar marinov, http:/geocities.com/h2428
cd()
{
local opt OPTIND
local new_dir adir
local cnt x2 index
# 기존 builtin cd 명령의 옵션을 사용할 경우 오류가 발생하는 것을 방지하기 위한 코드
if ! [ $# -eq 0 ]; then
if [[ $# -eq 2 && $1 = "--" ]]; then
shift
else
if ! { [ $# -eq 1 ] && [[ $1 =~ ^(-[0-9]{,2}|-|--|[^-].*)$ ]] ;}
then
builtin cd "$@"
return
fi
fi
fi
if [ "$1" = "--" ]; then
dirs -v
return
fi
new_dir=$1
[ -z "$1" ] && new_dir=$HOME
# 인수가 '-숫자' or '-' 형태일 경우
if [[ "$new_dir" =~ ^(-[0-9]{,2}|-)$ ]]; then
index=${new_dir:1}
[ -z "$index" ] && index=1
adir=$(dirs +$index)
[ -z "$adir" ] && return 1
new_dir=$adir
fi
# 디렉토리 이름 앞에 '~' 문자가 있을 경우 $HOME 으로 대체
[ "${new_dir:0:1}" = "~" ] && new_dir=$HOME${new_dir:1}
# $new_dir 로 cd 하고 동시에 stack 의 top 에 항목을 add 합니다.
pushd -- "$new_dir" > /dev/null
[ $? -ne 0 ] && return 1
new_dir=$(pwd)
# 15 개의 history 만 사용할 것이므로 16번째 항목이 생길경우 stack 에서 삭제합니다.
popd -n +16 &> /dev/null
# 마지막으로 기존 history 를 검색해 현재 디렉토리와 중복되는 항목이 있으면 삭제합니다.
for ((cnt=1; cnt <= 15; cnt++)); do
x2=$(dirs +$cnt 2>/dev/null)
[ $? -ne 0 ] && return
[ "${x2:0:1}" = "~" ] && x2=$HOME${x2:1}
if [ "$x2" = "$new_dir" ]; then
popd -n +$cnt > /dev/null
let cnt--
fi
done
return 0
}
export -f cd