한국 휴렛팩커드 소프트웨어 지원사업부
ASE 소 운 영
1. Shell Program 소개
u Shell 종류
/usr/bin/sh POSIX Shell
/usr/bin/ksh Korn Shell
/usr/old/bin/sh Bourne Shell
/usr/bin/csh C Shell
/usr/bin/keysh Key Shell
/usr/bin/rksh Restricted Korn Shell
/usr/bin/rsh Restricted Shell
u Shell Startup 파일
Korn Shell /etc/profile -> $HOME/.profile -> $HOME/.kshrc
Bourne Shell /etc/profile -> $HOME/.profile
POSIX Shell /etc/profile -> $HOME/.profile -> $HOME/.kshrc
C Shell $HOME/.login -> $HOME/.cshrc
2.Shell Parameter
u Parameter Substitution
l Parameter Setting
# Parameter=Value
# 변수명=값 : Named Parameter
l Parameter의 Unsetting
# unset parameter
# unset 변수명
u Command Substitution
# $(command) # `command`
# XX="12345" # echo $XX 12345 # HOST=‘hostname‘ # echo $HOST : # HOST=`hostname` 문장은 # HOST=$(hostname)과 같다 ssosvr3 : 즉, `command` 문장과 $(command)는 같은 뜻이다 # PS1=‘hostname‘':$PWD# ' # PS1=$(hostname)':$PWD# '; echo $PS1 ssosvr3:/# # W1="A"; W2="B"; W3="C" # WORD=${W1}AA${W2}BB${W3}CC # echo $WORD AAABBBCCC # unset WORD |
- $10과 ${10}은 다르다. 왜냐하면 $10은 positional parameter $1값에
0값이 붙여서 출력되며, ${10}은 positional parameter 10번째의 값을
나타내기 때문이다.
u Positional Parameter(위치변수)
shell-script arg1 arg2 arg3 arg4
$0 $1 $2 $3 $4
Positional Parameter : $1,$2,$3,$4
$0 shell script명을 나타낸다
$1 첫번째 argument를 나타낸다. 즉, arg1
$2 두번째 argument를 나타낸다. 즉, arg2
$* "arg1 arg2 arg3 arg4 ..." 즉,모든 argument와 같다.
$@ "arg1" "arg2" "arg3" "arg4..." 즉,개개의 argument와 같다.
$# 모든 argument의 갯수
$? 마지막으로 수행된 명령어가 return한 값
$$ 현재 shell script를 수행하고 있는 shell의 process id(pid)
$! 현재shell에서 수행한 마지막 background의 pid
$_ shell command의 마지막 argument를 가르키며,shell start시에는
shell의 절대 PATH를 가르킨다.
# set aaa bbb ccc ddd eee fff - set명령어를 옵션없이 사용하면 positional parameter를 setting한다. # echo $0 sh 현재shell를 나타낸다. # echo $1 aaa # echo $# 5 $# 은 argument의 개수를 나타낸다. # echo $* "aaa bbb ccc ddd eee fff" # echo $@ "aaa" "bbb" "ccc" "ddd" "eee" - "$*" 와 "$@" 의 차이점은 $*은 Positional parameter의 모든값을 하나의 문자열(string)으로 취급하며 $@ 는 string을 개개의 문자열로 취급한다. # echo $$ 7637 : shell의 process id |
${parameter} parameter의 값. 이것은 {}뒤에 붙어있는 문자나
숫자,_ 와 같은문자와 함께 사용할 때 필요하다.
${#parameter} parameter값의 문자수. ${#*}나 ${#@}은 positional
parameter의 개수를 나타낸다.
${#identifier[*]} 배열 identifier에서 element의 수를 출력한다.
${parameter:-word} parameter가 set되고 NOT NULL이면 parameter값을 출력하고,
그렇지 않으면 word의 값을 출력한다.
${parameter:+word} parameter가 set되고 NOT NULL이면 word의 값을 출력하고,
그렇지 않으면 아무것도 출력하지 않는다.
${parameter:=word} parameter가 set되고 NOT NULL이면 parameter의 값을
출력하고, 그렇지 않으면 word의 값을 출력하고 parameter에
word의 값을 assign한다. Positional parameter는
이렇게 setting할 수 없다.
${parameter:?word} parameter가 set되고 NOT NULL이면 parameter값을
출력하고, 그렇지 않으면 word를 출력하고 shell를
exit한다. word가 생략되면 화면에 표준출력된다.
# dir1=/home/tmp # echo ${dir1:-/usr/bin} /home/tmp # unset X # echo ${X:-"X is unset"} X is unset : X가 unset또는 null이면 word가 출력된다. # echo ${dir1:+/usr/bin} /usr/bin : dir1이 null이면 아무것도 출력되지 않는다. # echo ${dir1:=/usr/bin} /home/tmp : dir1이 unset되었거나 null이라면 /usr/bin이 출력된다. # echo ${dir1:?/usr/bin} /home/tmp # echo ${#dir1} 10 : /users/tmp 의 총 문자갯수 |
${parameter#pattern} pattern이 parameter값의 첫문자와 같으면 그문자를
${parameter##pattern} 포함한 부분은 delete된다. ##은 wild card(*)시 사용함.
${parameter%pattern} pattern이 parameter값을 끝문자와 같으면 그문자를
${parameter%%pattern} 포함한 문자는 delete된다. %%은 wild card(*)시 사용함.
# XX=/a/b/c/d/a/b # echo ${XX#*a} /b/c/d/a/b # echo ${XX##*a} /b # echo ${XX%a*} /a/b/c/d/ # echo ${XX%%a*} / |
# AA="12345123" # echo ${AA#1} 2345123 # echo ${AA##*1} 23 # echo ${AA%3} 1234512 # echo ${AA%%3*} 12 |
# echo ${AA#5} 12345123 # echo ${AA##*5} 123 # echo ${AA##*3*} # echo ${AA##6*} 12345123 |
u Tilde(~) Substitution
만약 user mary의 home directory가 /users/mary라면 # echo $HOME /users/mary # echo ~ : ~ 는 user의 home directory를 나타낸다. /users/mary # echo $PWD /users/mary/tmp # ls ~+/x* : ~ 다음의 + 는 현재directory 즉, $PWD의 값을 가르킨다. /users/mary/tmp/x_file1 /users/mary/tmp/x_file2 # echo $OLDPWD /users/mary/mail # ls ~-/f* : ~ 뒤의 - 는 이전 directory 즉, $OLDPWD의 값을 가르킨다. /users/mary/mail/from.mike /users/mary/mail/from.nick |
u Shell Command Grouping
l ( command ) : subshell grouping
shell은 마치 또다른 script를 call한것처럼 subshell
환경에서 command를 수행한다.
l { command ;} : brace grouping
shell은 현재의 shell 환경에서 연속해서command를
수행하며 마지막에 반드시 ;(세미콜론)을 써야한다.
# vi test1.sh #! /usr/bin/sh # (command)의 Example A="aaa" B="bbb" C="ccc" ( A="AAA" B="BBB" C="CCC" echo "PID $$ : $A $B $C" ) echo "PID $$ : $A $B $C" :wq # sh test1.sh PID 28999 : AAA BBB CCC PID 28999 : aaa bbb ccc |
# vi test2.sh #! /usr/bin/sh # {command;}의 Example A="aaa" B="bbb" C="ccc" { A="AAA" B="BBB" C="CCC" echo "PID $$ : $A $B $C" ;} echo "PID $$ : $A $B $C" :wq # sh test2.sh PID 28955 : AAA BBB CCC PID 28955 : AAA BBB CCC |
u Shell Script의 수행
# sh shell_script
# ksh shell_script
# chmod 777 shell_script
# ./shell_scipt
u Shell Script Comment
l shell script에서 comment는 첫라인에 # symbol를 넣는다.
l shell script에서 첫라인의 #! /usr/bin/sh의 의미는 이 shell은
Posix shell로 수행한다는 의미이다.
u Input and Output
stdin(0) standard input으로서 default는 keyboard이며
file descriptor값은 0 이다.
stdout(1) standard output으로서 default는 terminal display이다.
file descriptor값은 1 이다.
stderr(2) standard error로서 default는 terminal displsy이다.
file descriptor값은 2 이다.
<word 표준입력(file descriptor 0)으로 word를 사용한다.
>word 표준출력(file descriptor 1)으로 word를 사용하며,
word라는 file이 생성된다.
>|word >word와 같으며 noclobber옵션이 설정되있어도 무조건 overwrite한다.
>>word word라는 file이 존재하면 file에 append한다.
없으면 word라는file을 생성한다.
<>word word를 입력으로 받아서 다시 word라는 file로 출력한다.
<<word shell prompt에서 word라는 글자를 만날때까지 command를 입력할 수
있으며 word라는 글자를 만나면 shell command가 수행된다.
<&숫자 file descriptor 숫자의 file에서 data를 입력받는다.
>&숫자 file descriptor숫자를 가진 file로 출력한다.
<&- 표준입력을 close하여 keyboard로부터 입력받지 못한다.
>&- 표준출력을 close하여 terminal로 출력하지 않는다.
# ftp -n -i << AAA >open mars >user root password >cd /users >mget * >close AAA # |
# vi datafile : data file작성 aaa bbb ccc :wq # vi read.sh exec 5< datafile : datafile을 file descriptor 5번으로 open한다. read -u5 X : 첫라인을 read하여 X변수에 assign한다. read -u5 Y : 둘째라인을 read하여 Y변수에 할당. read -u5 Z : 셋째라인을 read하여 Z변수에 할당. exec 5<&- : file descriptor 5번 file을 close한다. echo "$X $Y $Z" : file descriptor은 3-9까지 쓸수있다. :wq # sh read.sh aaa bbb ccc |
u 조건 표현식
test 또는 [ ... ] Integer,string.file등에 모두사용(old syntax)
(( ... )) Integer에만 사용(new syntax)
[[ ... ]] string,file에만 사용(new syntax)
l String 표현식 # man test 참조
----------------------------------------------------------------------------
[ -b file ] file이 존재하고 block special file이면 참
[ -c file ] file이 존재하고 character special file이면 참
[ -d file ] file이 존재하고 directory이면 참
[ -e file ] file이 존재하면 참
[ -f file ] file이 존재하고 ordinary file이면 참
[ -g file ] file이 존재하고 setgid bit가 set되있으면 참
[ -h file ] file이 존재하고 symbolic link되었으면 참
[ -k file ] file이 존재하고 sticky bit가 set되었으면 참
[ -p file ] file이 존재하고 fifo special file또는 pipe이면 참
[ -r file ] file이 존재하고 readable하면 참
[ -s file ] file이 존재하고 file size가 0보다 크면 참
[ -u file ] file이 존재하고 setuid bit가 set되 있으면 참
[ -w file ] file이 존재하고 writable하면 참
[ -x file ] file이 존재하고 executable하면 참
[ -L file ] file이 존재하고 symbolic link이면 참
[ -O file ] file이 존재하고 user가 effective user id와 같으면 참
[ -G file ] file이 존재하고 group이 effective group id와 같으면 참
[ -S file ] file이 존재하고 socket이면 참
-----------------------------------------------------------------------------
[ -n string ] string의 길이가 non zero면 참
[ -z string ] string의 길이가 zero이면 참
[ string ] string이 not null string이면참
# if [ -f /etc/rc.config ] ; then # if [ ! -d /usr/bin ] ; then # if [ -z "$NODENAME" ] ; then # if [ -x /usr/dt/bin/dtrc ] ; then # if [[ -n "$NAME" ]] ; then # if [[ -s /var/spool/lp/pstatus ]] ; then # if [[ -r /var/run/mrouted.pid ]] ; then # if [[ -z "$pid" ]] ; then # if /usr/sbin/envd ; then # if /sbin/local_is_root ; then # if [ "$ARRAYMON_PID" ] ; then # if [ "$START_OV500" ] ; then |
[ file1 -nt file2 ] file1이 존재하고 file2보다 newer이면 참
[ file1 -ot file2 ] file1이 존재하고 file2보다 older이면 참
[ file1 -ef file2 ] file1이 존재하고 file2와 equal file이면 참
# if [ /sbin/init.d/spa –nt /sbin/init.d/set_date ] ; then # if [ /aaa –ot /bbb ] ; then # if [ /ccc –ef /ddd ] ; then |
[ string1 = string2 ] string1과 string2가 같으면 true
[ string1 = pattern ] string1과 pattern이 같으면 true
[ string1 != string2 ] string1과 string2가 같지않으면 true
[ string1 != pattern ] string1과 pattern이 같지않으면 true
[ string1 < string2 ] string1이 string2보다 작으면 true
[ string1 > string2 ] string1이 string2보다 크면 true
# if [ "$pid" = "" ] ; then # if [ X$pid != "X" ] ; then # if [ $HOST != `hostname` ] ; then # if [ "$MWASTART" > "1" ] ; then # if [[ $? = 255 ]] ; then |
[ exp1 -eq exp2 ] exp1과 exp2가 같으면 참(equal)
[ exp1 -ne exp2 ] exp1과 exp2가 같지 않으면 참(not equal)
[ exp1 -lt exp2 ] exp1이 exp2보다 작으면 참(less than)
[ exp1 -gt exp2 ] exp1이 exp2보다 크면 참(greater than)
[ exp1 -le exp2 ] exp1이 exp2보다 작거나 같으면 참(less than or equal)
[ exp1 -ge exp2 ] exp1이 exp2보다 크거나 같으면 참(greater than or equal)
# if [ $x –ne 0 ] ; then # if [ $? –eq 0 ] ; then # if [ "$RWHOD" –eq 1 ] ; then # if [[ "$rval" –eq ${EXIT_NA} ]] ; then # while [ ${CNT} –le ${MAX_NISCHECKS} ] ; then # if [ $# -ge 0 ] ; then # if [ "$XX" –gt "$YY" ] ; then # if [ "$X" –lt 1 ] ; then # if [ $# -ne 1 ] ; then # if [ `grep $HOSNAME /etc/mail/sendmail.cw|wc –l` -eq 0 ] ; then |
( expression ) expression이 참이면 참
! expression Binary NOT 연산자
exp –a exp2 Binary AND 연산자, 우선순위가 –o 보다 높음.
exp –o exp2 Binary OR 연산자
exp1 && exp2 exp1과 exp2가 모두 참이면 참
exp1 || exp2 exp1가 참이거나 exp2가 참이면 참
# if [ "$GATED" –eq 0 –a "X$pid" = "X" ] ; then # if [ "$CRON" –eq 1 –a –x /usr/sbin/cron ] ; then # if [ "$NIS_DOMAIN" –a –f /usr/bin/domainname ] ; then # if [ "$NIS_MASTER" –ne 0 –o "$NIS_SLAVE" –ne 0 ] ; then # if [ "$9" = 'S' ] || [ "$9" –lt '2' ] ; then # if [ "$VTDAEMON_START" –eq 1 ] && [ -x /usr/sbin/vtdaemon ] ; then # if [[ -r /usr/sbin/swagentd# ]] && [[ -h /usr/sbin/swagentd ]] ; then # if [ $status !=2 –o –z "$DOMAIN" –o –z "$SERVER" ] ; then # if (( status == 0 )) && [[ -n $PROTO ]] ; then |
l Integer 표현식
(( integer1 == integer2 )) integer1과 integer2가 같으면 참
(( integer1 != integer2 )) integer1과 integer2가 같지 않으면 참
(( integer1 < integer2 )) integer1이 integer2보다 작으면 참
(( integer1 > integer2 )) integer1이 integer2보다 크면 참
(( integer1 <= integer2 )) integer1이 integer2보다 작거나 같으면 참
(( integer1 >= integer2 )) integer1이 integer2보다 크거나 같으면 참
# if (( $? != 0 )) ; then # while ((n>0)) # if ((n<2) || !length(part[2])) ; then # if ( $1 != mypid ) ; then # if (( $1 > $2 )) ; then |
3.Shell Programming
u if 조건문
if 조건문 then 명령어 [elif 조건문 then 명령어] [else 명령어] fi |
if 조건문; then 명령어; [elif 조건문; then 명령어;] [else 명령어;] fi |
:wq# vi if1.sh X=hello if [ $X = hello ] then echo "Welcome" else echo "Goodbye" fi :wq # sh if1.sh Welcome |
# vi if2.sh if [ -f temp ] then mv temp temp1 elif [ -f temp1 ] then mv temp1 temp2 fi :wq # sh if2.sh |
u case 조건문
case 변수 in 변수값1|변수값2…) 명령어;; 변수값3|변수값4…) 명령어;; *) 명령어;; esac |
# vi case.sh case $1 in -d|-r) rmdir $dir1 echo "directory removed" ;; -o) echo "option -o" ;; *) echo "Invalid option,Try again..." ;; esac :wq # chmod 777 case1.sh # ./case.sh -o option -o |
u while 반복문
while 조건문 do 명령어 done |
- 다음은 모두 같은 while문이다.
while [ 1 ] do echo "Test" done |
while true do echo "Test" done |
while [ : ] do echo "Test" done |
while : do echo "Test" done |
# vi while1.sh count=$(who|grep -v root|wc -l) while [ "$count" -gt 0 ] do echo "Users still logged in..." sleep 1 count=$(who|grep -v root|wc -l) done :wq # sh while1.sh |
# vi while2.sh # /usr/bin/sh # print -n "Enter a value : " read Value print "Thank You" count=0 while [ "$count" -lt "$Value" ] do (( count=count + 1 )) print "Still sleeping for the $count th time..." sleep 2 done print "End of $0" :wq # sh while2.sh |
u for 반복문
for 변수 [in 변수값1,변수값2,…] do 명령어 done |
# vi for1.sh for name in $(cut -d -f1 /etc/passwd) do mailx $name < message.txt echo "Mail sent to $name" done :wq # sh for1.sh |
# vi for2.sh if [[ ! -d "$1" ]] then exit 1 fi filename=$(ls $1) for onefile in $filename do if [[ -f ${1}/$onefile ]] then ll ${1}/$onefile elif [[ -d ${1}/$onefile ]] then ll -d ${1}/$onefile fi done :wq # sh for2.sh /etc |
u until 반복문
until 조건문 do 명령어 done |
# vi until.sh count=$(who|grep -v root|wc -l) until [ "$count" -eq 0 ] do echo "Users still logged in..." sleep 1 count=$(who|grep -v root|wc -l) done :wq # sh until.sh |
u select 반복문
select 변수 [in 변수값1,변수값2,…] do 명령어 done |
- select문은 PS3 prompt를 사용한다. PS3 shell 변수의 기본값은 #? 이다.
- 변수는 변수값1,변수값2,… 등이 할당된다.
- 입력된 변수의 값의 숫자는 REPLY라는 shell변수에 저장된다.
- exit,return,break 등의 명령어로 반복문을 빠져나올수 있다.
- [in 변수값1,변수값2,…]가 없을경우에는 Positional Parameter를 사용한다.
# vi edit.sh ### Edit the file ### select menu in $(ls) "Exit" ; do case $menu in Exit) exit;; "") echo "Invalid selection. Try again!";; *) cp $menu $menu.bak; vi $menu ;; esac ; done :wq |
# vi color.sh select color in red blue green do echo "$color is an $color color" echo "$REPLY is a REPLY value" done :wq # sh color.sh 1)red 2)blue 3)green #? 1 red is an red color 1 is a PEPLY value #? 2 blue is an blue color 2 is a REPLY value #? ^C # |
# vi select.sh PS3="Enter your choice =>" select menu in "full backup" "partial backup" do case $menu in "full backup") fbackup –0uf /dev/rmt/0m –i /stand echo "Full backup has begun" exit 0;; "Partial backup") fbackup –0uf /dev/rmt/0m -i /opt echo "Partial Backup has begun" return;; *) echo "$REPLY is an invalid option. Try again!";; esac done :wq # sh select.sh |
# vi nest.sh #### Nested Select Command Example ### #! /usr/bin/sh PS3="Main Choice by number=>" select menu in "List Files" "Exit" do case $menu in "List Files") PS3="Sub Choice by number=>" select ls_option in "Short" "Long" "Main" do case $ls_option in "Short") lsf;; "Long") ll;; "Main") PS3="Main Choice by number=>" ## Restore Prompt break 1 ;; ## exit inner loop "") echo "$REPLY is an invalid option. Try again!";; esac done ;; "Exit") exit;; "") echo "$REPLY is an invalid option. Try again!";; esac done :wq # sh nest.sh |
u Function(함수)
function 함수명 { shell script } |
함수명() { shell script } |
- shell script안에 선언할수도 있고 밖에 선언할수도 있다.
- 함수명이나 argument로 called될수 있다.
- 같은 process를 반복적으로 사용할때 유리하며 debugging하기가 쉽다.
- typeset -xf name 으로 함수명을 export하여 global 함수로 선언할수 있다.
# vi func1.sh function exef { if [ -x $1 ] then echo "$1 is executable" fi } for file in `ls` do exef $file done :wq # sh func1.sh |
# vi func2.sh Uppercase() { echo $* | tr "[a-z]""[A-Z"]" } print -n "Enter in a string:" read string upper_string=$(Uppercase $string) echo "The uppercase string is: $upper_string" :wq # sh func2.sh |
# vi func3.sh : Recursive Fuction bottom_up { typeset SAVEPWD echo "\nDirectory being listed is: $PWD\n" lsf if [ "$PWD" != "/" ] then SAVEPWD=$PWD cd .. bottom_up cd $SAVEPWD else echo "That's the end!" fi } :wq # sh func3.sh |
u Array(배열)
- shell script에서 사용할수 있는 배열은 1차원배열이다.
- 배열요소(element)는 최대 512-1024까지 쓸수 있다.
- 배열요소는 [0]부터 [1023]까지 쓸수 있다.
- Array subscript인 [N]에서 N은 integer또는 integer expression을 쓸수 있다.
# X[0]=first # X[1]=second # X[2]=third # echo ${X[1]} second # echo ${X} : ${X}는 ${X[0]}과 같음 first # echo ${X[*]} : '*'나 '@'는 모든 요소를 가르킴 first second third # echo ${#X[*]} 3 |
# i=3 # X[2*(i+1)]=10 # print ${X[8] 10 |
# set -A YY 100 200 300 : set -A는 변수를 배열로 선언한다. # print ${YY[0]} ${YY[1]} ${YY[2]} 100 200 300 # set +A YY 150 # print ${YY[@]} 150 200 300 |
4.Shell Command
u : 명령어
- ':' 명령어는 아무것도 수행하지 않으며, 어떤 영향도 미치지 않는다. '0'값이 return됨.
# vi xx.sh if [ -f /opt ]; then ls else : 아무것도 수행하지 않는다. fi :wq |
u . 명령어
# . /etc/profile
- /etc/profile이라는 프로그램을 수행한다. 이는 sh나 ksh처럼 또하나의 shell을 fork하여
프로그램을 수행하지 않으며 이 프로그램은 수행가능한 permission이 없어도 된다.
즉 이 파일은 'x' permission이 없어도 된다.
u alias 명령어
alias [-x] [ name[=value] … ]
# alias : 현재 setting된 모든 alias를 display # alias a=alias # a x=lsf # alias i=' > echo Users logged in are: > who|sort > echo I am `whoami`' # i : alias문을 수행한다. # unalias i : alias변수 i를 unsetting한다. # unalias -a : shell command에서 typing한 모든 alias를 해제한다. # alias -x who='who|sort' : Korn shell에서 who를 export하여 subshell에서도 사용가능하다. |
u break 명령어
break [n]
- for,while,until,select문과 같은 반복문에서 exit할 때 사용한다.
- n을 쓰면 n레벨만큼 loop를 exit한다.
# vi break.sh for file in x y z none do if [ -x $file ]; then echo $file break fi done :wq |
u command 명령어
command [arg …]
- argument를 command로서 취급한다.
# command lsf : lsf를 command로 사용한다. # command aaa : aaa를 command로 사용한다. |
u continue 명령어
continue [n]
- for,while,until,select문과 같은 반복문에서 continue이하의 문을 수행하지 않고
다시 시작한다.
- n을 쓰면 n번째 반복문을 다시 시작한다.
# vi con.sh for file in x y z do if [ -x $file ]; then continue echo "$file is executable" fi echo $file is not executable done :wq |
u echo 명령어
echo [arg …]
# echo 'This is a' $var 'example.' # echo "This is a $var example." # echo "Enter your user name: \c" > read user > echo 'User is' $user |
echo 에서 Escape Character
\b backspace \c continue line. new line을 하지 않고 계속 붙여서 print한다 \f form feed |
\n new line \r carriage return \t tab \v vertival tab \\ backslash |
u eval 명령어
eval [arg …]
- argument를 input으로 받아서 명령어로 수행하며 argument는 command나 shell
script가 될수 있다.
# cmd='ps -ef > ps.out' # eval $cmd # eval "grep jones $file|set|echo $1 $2 $3" |
u exec 명령어
exec [arg …]
- 새로운 process나 subshell을 만들어서 argument를 수행하지 않고 현재 shell로
명령어를 바로 수행한다.
# exec 3< file file desciptor number 3으로 file을 open한다.
# ecec 2> /dev/null 표준에러를 /dev/null로 출력한다.
u expr 명령어 # man expr 참조
expr expression {+,-,\*,/} expression
expr expression {=,\>,\>=,\<,\<=,!=} expression
expr string1 : string2
# a=15 # expr $a + 5 20 # count=`expr $count + 5` # A=batman # expr substr $A 1 3 bat # expr index $A m 4 |
u fc 명령어
fc [-r] [-e example] [first [last]]
fc –l [-nr] [first [last]]
fc –s [old=new] [first]
fc –e – [old=new] [command]
- fc command는 history file을 list하거나 history file에서 command를 edit할 수있다.
# fc –l : history file의 내용을 display한다. # fc –l 20 25 # fc –l 10 # fc –e vi 15 20 # fc –e - : 방금 실행한 command를 다시 실행한다. # r 명령과 같다. # fc –e – ls=cd |
u let 명령어
let "expression"
(( expression ))
- let는 산술 표현을 가능하게 하며 long integer 계산을 한다.
Operator |
Description |
- ! / % + - < <= > >= == != = |
unary minus logical negation 곱하기,나누기,몫 더하기,빼기 비교 같다,같지 않다 변수 할당 |
# x=10 # y=2 # let x=x+2 # echo $x 12 # let "x=x/(y+1)" # echo $x 4 # (( x=x+1 )) # echo $x 5 |
# x=12 # let "x<10" # echo $? 1 # (( x > 10 )) # echo $? 0 # if (( x > 10 )) >then echo x greater >else echo x not greater >fi x greater |
u read 명령어
read [-r] name… : POSIX Shell only
read [-prsu] [name] : Korn Shell only
-r 라인연속으로 쓰인 라인끝의 \를 해석하지 않는다.
-un file descriptor n 으로부터 input을 read한다.
# vi read.sh while read -r xx yy do printf "%s %s \n" "$yy" "$xx" done < input_file :wq |
u return 명령어
return [n]
- 함수의 실행을 마치고 calling shell script에게 exit status n을 return한다.
- n이 없으면 return status는 함수의 마지막 command의 값이다.
- return이 함수의 밖에서 수행되면 exit로서 실행된다.
# vi return.sh search() { if grep xxx "$1" > /dev/null 2>&1 then return 1 else return 2 fi } :wq # sh return.sh filename |
u set 명령어
l Positional Parameter값 setting
# set spring summer fall winter # echo $3 fall # echo $* spring summer fall winter |
l Positional Parameter Sorting
# set third first second # echo $1 $2 $3 third first second # set –s : 값을 lexical order로 sorting함 # echo $1 $2 $3 first second third # set +s : unsetting |
option option-name meaning
--------------------------------------------------------------------------------
set –a allexport 모든 parameter가 자동으로 export됨. == set -o allexport
set -C noclobber #date>XX시 >로 overwrite하지못하게 함. date>|XX로는 가능
set –e errexit shell command fail시 즉시 logout또는 shell을 exit함
set –f noglob # ls * 시wild card문자를 인식못함
set –h trackall
set –k keyword
set –m monitor Background jogs이 각각다른 process group에서 수행되고
작업이 끝나면 message를 report함
set –o set –o monitor와 같이 option-name에 붙여서 옵션을
setting함
set –s positional parameter를 sort함
set –t shell을 exit한후에 command를 수행함
set –u nounset substituting시 unset parameter를 error로 취급함
set –v verbose command를 display한후 command 수행
set –x xtrace command수행시 command와 argument까지 print함.
shell script의 debug mode로 사용함.
set 현재 setting된 모든 shell variable을 list함
set - -x와 –v option을 turn off하고 flag에 대한 argument
검사를 하지 않음
set -- 옵션의 어떤 변화도 하지못하게 함. # set -- -;echo $1
file명으로 시작하는 file을 rm할 경우 # set -- -;rm –aaa
# set –o ignoreeof : ignoreeof라는 옵션을 turn on # set +o vi : vi의 옵션을 turn off # set –o noglob : noglob옵션을 turn on 시키고 wild card인 *,[],-,!,? 등을 shell이 해석하지 못하게함 # set –o noexec : shell의 syntax error를 check하기위해 사용. 이 옵션은 interactive shell에서는 사용되지 않으며 shell script에서만 수행됨. noexec 옵션은 실제로 shell을 수행하지 않으면서 shell의 syntax error만을 check하는 명령어다. |
# vi set1.sh set –o noexec echo "This is test ls cp /aaa /bbb :wq # ksh set1.sh set1.sh: syntax error at line 2 : '"' unmatched |
# vi set2.sh set –x ls echo "The Test" set +x lsf :wq # sh set2.sh |
u shift 명령어
shift [n]
shift command는 positional parameter($1,$2,$3..)의 내용을 왼쪽순으로 move한다.
# vi shift1.sh yflag=0 zopt="" for arg in "$@" do if [ "x$arg" = x-y ] then yflag=1 shift else zopt="$2" shift 2 fi done :wq |
u trap 명령어
trap [command] [signal]
- signal 값은 # kill –l또는 # man kill 명령어로 볼수 있음.
# trap "echo 'Command Failed'" 2 : ^C(interupt)를 치면 echo 문장이 수행됨. # trap : trap 명령을 수행한후 옵션이 없이 trap명령을 수행하면 현재 setting된 모든 trap내용을 보여줌 # trap "" 1 2 3 : 1}HUP 2)INT 3)QUIT가 입력되도 무시하라. # trap "echo logout" 0 : signal이 '0' 이면 NULL signal로서 shell에서 exit할때 command가 수행된다. |
u typeset 명령어
typeset [-][+]옵션 변수명[=변수값]
option meaning
-----------------------------------------------------------------------------
[-] 변수명의 속성을 setting
[+] 변수명의 속성을 turn off
-Ln 왼쪽의 공백을 제거하고 왼쪽에서 n숫자만큼 cut
-Rn 왼쪽에 공백을 채우고 오른쪽에서 n숫자만큼 cut
-Z 오른쪽으로 shift하고, 첫번째 문자가 숫자이고 –L옵션과 같이
쓰지 않았으면 왼쪽에 숫자0을 채움
-i 변수명을 integer로 선언
-f 변수명이 아니라 함수명으로 변수를 선언
-l 모든 영문대문자를 소문자로 변환
-u 모든 소문자를 대문자로 변환
-r 변수를 read-only로 만듬,즉 변수를 상수로 만듬
-x 변수를 export함, 즉 변수를 전역변수로 만듬
-----------------------------------------------------------------------------
# typeset
현재 setting되어있는 변수의 data type을 보여줌
# typeset AA
AA변수를 string변수로 선언,또한 함수내에서 Local변수 즉 지역변수로 선언
하지만, shell에서 변수는 default로 string data type임
# DATA="Today we had very HOT weather" # typeset –u DATA # echo $DATA TODAY WE HAD VERY HOT WEATHER # typeset +u DATA : DATA변수의 속성을 turn off # DATA="as of the "${DATA} # echo $DATA as of the TODAY WE HAD VERY HOT WEATHER # AAA=123456789 # typeset –L3 AAA # echo $AAA 123 # typeset –LZ X=00005 # print $X 5 |
# typeset –i X : 변수X를 integer로 선언 # integer X와 같음 # typeset –i2 X : 변수X를 2진수로 선언 # typeset –i8 X : 변수X를 8진수로 선언 # typeset –i10 X : 변수X를 10진수로 선언 # typeset –i16 X : 변수X를 16진수로 선언 # typeset -r Y=123 : 변수Y를 readonly변수로 선언 # readonly Y=123과 같음 # typeset -f : 모든함수와 그 값을 display함 # typeset -xf : export된 모든함수와 그 값을 display함 # typeset -xf XX : 함수명 XX를 export하여 global function으로 선언함 |
u ulimit 명령어
ulimit [-f] [n]
- ulimit command는 child process나 subprocess에 의해 사용된는 resources를 제한한다.
# ulimit : 현재 limit값을 보여준다
# ulimit –f 1000 : 현재process나 향후 process가 write할 수 있는
file size를 1000 block(1000*512 byte)으로 제한한다.
# ulimit –f unlimited : child process가 생성할 수 있는 size의 제한을 없앤다.
5.Regular Expression(정규 수식)
u Pattern Matching과 Regular Expression의 비교 - # man 5 regexp참조
Pattern Matching |
Regular Expression |
- POSIX shell에서 사용 - file name생성과 case문에서 사용 |
- UNIX command와 Text Editor에서 사용 (ed,vi,ex,sed,awk,expr,grep) |
- file name을 match한다 |
- character string을 match한다 |
- file name을 substitute한다 |
- string을 search해서 substitute한다 |
- 사용되는 특수문자 ?, *, [ - ], ! |
- 사용되는 특수문자 ., [], -, ^, $, * |
u 하나의 문자와 Match - .(dot)
A. : AB,Ab,AA,A9등과 같이 A다음에오는 어느한문자와 match
... : 연속된 3문자와 match
# man 5 regexp|col -b|expand > regexp.man
# grep 'RE.' regexp.man : RE다음에오는 어느한문자와 Match되는 라인만 출력
u 문자의 시작과 Match - ^
^abc : 첫문자가 abc로 시작되는 문자와 match. abc,abcabc,abcdef등과 match
^C : 문자의 시작에서 C와 match
^C$ : 하나의 문자 C와 match
^.$ : 하나의 문자로만 구성된 문자와 match
^[ABC] : 첫문자가 ABC로 시작되는 문자와 match
u 문자의 끝과 Match - $
abc$ : 끝문자가 abc로 끝나는 문자와 match. defgabc,cccabc,abc등과 match
^...$ : 3개의 문자로만 구성된 문자와 match
\.$ : 문자의 끝에서 마침표(.)과 match
\*$ : 문자의 끝에서 (*)와 match
u 문자 Match - []
[Tt]he : The나 the라는 글자를 search
h[iau]t : hit,hat,hut의 글자와 match
[ABC] : A,B,C를 포함하는 문자와 match
u 범위를 포함하는 문자와 Match - [ - ]
[a-z] : 소문자 a부터 z까지 어느문자와도 match
[0-9] : 0-9까지 어떤 하나의 숫자와 match
[0-57] : 0,1,2,3,4,5,7과 match
[a-c5-8X-Z] : a,b,c,5,6,7,8,X,Y,Z중 하나의 문자와 match
[0-3-] : 0,1,2,3,-와 match
u Complemented문자 Match - [^ ]
[^ ] : 공백이 아닌 한문자와 match
[^0-9] : 0-9까지 숫자가 아닌 하나의 모든문자와 match
[^a-zA-Z] : 영문 알파벳이 아닌 문자나 숫자와 match
[012^] : 0,1,2,^와 match
^[^a-z]$ : 소문자을 제외한 나머지 문자중 하나와 match
# man 5 regexp|col -b|expand > regexp.man
# grep '^$' regexp.man|wc -l : 공백라인수를 출력한다.
# TMOUNT=`/sbin/mount | grep '^/tmp(/| )' | wc -l`
# grep -q -e "^/usr/bin$" -e "^/usr/bin:" -e ":/usr/bin:"\
-e ":/usr/bin$" /etc/PATH
u Null 또는 여러 같은문자와 Match - *,+,?
B* : Null문자,B,BB,BBB...등과 match
AB*C : AC,ABC,ABBC...등과 match
A+ : A,AA,AAA...등과 match
AB+C : ABC,ABBC,ABBBC...등과 match
A? : Null문자 또는 A와 match
AB?C : AC,ABC와 match
[A-Z]+ : 하나이상의 대문자와 match
(AB) : AB문자와 match
(AB)+C : ABC,ABABC,ABABABC...등과 match
AB.*XYZ : ABXYZ,ABCXYZ,ABCCCCXYZ...등과 match
u 특수문자 Match - \
\* : 특수문자 *와 match
\$ : 특수문자 $와 match
\\ : 특수문자 \와 match
\\\\\.\*$ : 문자의 끝에서 \\.* 와 match
u Subexpression - \( ... \)
- \(...\)구문을 사용한다.
- subexpression과 match하는 문자를 recall하기위해 '\숫자'를 사용한다.
- '\숫자' 는 1-9까지 쓸수있다.
- \1 은 1번째 subexpression,\2 는 2번째 subexpression을 나타낸다.
# who
root console Oct 23 13:01
root ttyp1 Oct 27 12:45
root pts/0 Oct 22 09:03
# who|sed 's/\([^ ][^ ]*\)[^A-Z][^A-Z]*\(.*\)/\2-->\1/'
Oct 23 13:01-->root
Oct 27 12:45-->root
Oct 22 09:03-->root
- 첫번째 /\([^ ][^ ]*\) 는 공백이 아닌 하나이상의 문자와 match하며 뒷부분의
\1 의 값과 같다.즉, 여기서는 username root를 가르킨다.
- 두번째 \(.*\) 는 최초로 대문자로 시작되는 문자와 match하며 뒷부분의
\2 의 값과 같다. 여기서는 Oct를 가르킨다.
6.Sed(Stream Editor)
u sed 형식
sed [-n] command input_file...
sed [-n] [-e command]... [-f script_file]... [input_file...]
-n 화면에 display하지 않는다. 단 p명령어일경우는 화면에 display한다.
-n옵션은 -e나 -f옵션중 하나와 같이 사용할수 있다.
-e command command를 editing하며, input file이 없으면 표준입력이 사용된다.
-f script input file에서 editing command의 script file을 수행한다.
- sed는 입력파일로부터 한라인씩 data를 read한다.
- sed는 default로 화면에 출력을 하며 input file을 modify하지 않는다.
# sed "s/UNIX/Unix/g" file1 > file2.new
# sed -e "s/Miss/Ms/g" -e "s/Mrs/Ms/g" file2
# sed -n "1,10p" file2
# cat script
1,10p
# sed -n -f script file2
u s(substitute)
[address [,address]] s/string_old/string_new/[flag]
flag meaning
g global substitution(전라인을 모두바꾼다)
p print line
w file file로 write한다
# sed "s/[Cc]omputer/COMPUTER/g" file1 # sed -e "1,5s/abc/xyz/" -e 's/kbs/mbc/' file1 > file2 # sed "/abcde/s/ab/AB/g" file1 # sed -e 's/abc/xyz/w file2' file1 # sed "3s/the/xyz/g" file1 # sed '3s/^the /xyz/' file1 # sed -e "/the/s/ for /xyz/g # cat file1| sed "/the/s/ for /xyz/gw file2 # sed "1,8s/aaa/bbb/g" file1 > file2 # sed "/^5/,/^15/s/from/FROM/g" # sed -e "/^The first time/,/^End of file/s/lsf/ll/g" # sed "1,$s/\/usr\/bin/\/sbin\/bin/g" |
u d(delete)
# sed "1,10d" fileA
- fileA에서 1-10라인까지 delete한다.
# sed "/^From/!d" mbox
- mbox file에서 From으로 시작되는 라인만 제외하고 모두 delete한다.
u p(print),l(list),=,q(quit),r(read),w(write)
p standard output에 print한다. -n옵션과 함께써도 print된다.
l nonprinting문자도 같이 표준출력한다.
= address 라인의 라인번호를 표준출력한다.
q 현재라인을 출력하고 sed를 종료한다.
r file file의 내용을 read하여 표준출력한다.
w file file에 address라인을 write또는 append한다.
# vi cap
One potato, teo potato,
three potato, four.
Five potato, six potato,
seven potato, more.
:wq
# sed -n "1,2p" cap
One potato, two potato,
three potato, four.
# sed -e "q" cap
One potato, teo potato,
# sed -e "/\./=" -e " /[A-Z]/w file1" cap
One potato, teo potato,
2
three potato, four.
Five potato, six potato,
4
seven potato, more.
# killproc() { for x in "$@" do pid=`ps -e |grep "$x" |sed -e 's/^ *//' -e 's/ .*//'` [ ! –z "$pid" ] && echo killing $x && kill $pid & done } |
# findproc() { pid=`ps –e |grep "$1" |sed -e 's/^ *//' -e 's/ .*//'` echo $pid } |
# killproc() { echo stopping $1 pid=`/usr/bin/ps -e | /usr/bin/grep "$1" | /usr/bin/sed -e 's/^ *//' -e 's/ .*//'` [ "$pid" != "" ] && kill $pid } |
# if [ "$RWHOD" –ne 1 ]; then rval=2 else pid=`ps -el | awk '( ($NF ~ /rwhod/) && ($4 != mypid) && ($5 != mypid)) { print $4 }' mypid=$$ ` if [ "X$pid" != "X" ]; then if kill $pid; then echo "rwhod stopped" else rval=1 echo "Unable to stop rwhod" fi fi fi # # # |
# ARRAYMON_PID=`ps -ef | awk '$0 ~ /.*arraymon*/ && $0 !~ /.*awk.*/ { print $2 }'` if [ "$ARRAYMON_PID" ] then echo "Killing disk array monitor daemon." kill -9 $ARRAYMON_PID sleep 2 ARRAYMON_PID=`ps -ef | awk '$0 ~ /.*arraymon*/ && $0 !~ /.*awk.*/ { print $2 }'` if [ "$ARRAYMON_PID" ] then echo "ERROR: Could not kill ${ARRAY_MONITOR_DAEMON}" fi fi # |
7.Shell Program 예제
-shell script를 위한 data file은 다음과 같다. # vi data 100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600 1200 800 400 0 :wq |
# vi exp1.sh if [[ ! -f "$1" ]] then echo "${0##*/}" exit 1 else filename=$1 fi exec 3< $filename : file descriptor 3으로 filename를 open typeset -i II=0 : XX를 integer로 선언 while read -u3 AA[0] AA[[1] AA[2] AA[3] do for II in 0 1 2 3 do (( total[II]=${total[II]} + ${AA[II]} )) done print "Subtotal : " print ${total[*]} done print "Total for the four columns are : " print ${total[@]} :wq # sh exp1.sh |
#!/usr/bin/sh ######################## /etc/profile ########################## trap "" 1 2 3 PATH=/usr/bin:/usr/ccs/bin:/usr/contrib/bin MANPATH=/usr/share/man:/usr/contrib/man:/usr/local/man if [ ! -d /usr/sbin ] then PATH=$PATH:/sbin else if [ -r /etc/PATH ] then grep -q -e "^/usr/bin$" -e "^/usr/bin:" -e ":/usr/bin:"\ -e ":/usr/bin$" /etc/PATH if [ $? -eq 0 ] then PATH=`cat /etc/PATH` else PATH=$PATH:`cat /etc/PATH` fi fi fi export PATH if [ -r /etc/MANPATH ] then MANPATH=`cat /etc/MANPATH` fi export MANPATH if [ -r /etc/TIMEZONE ] then . /etc/TIMEZONE else TZ=MST7MDT export TZ fi if [ ! "$VUE" ]; then if [ "$TERM" = "" -o "$TERM" = "unknown" -o "$TERM" = "dialup" \ -o "$TERM" = "network" ] then eval `ttytype -s -a` fi export TERM if [ "$ERASE" = "" ] then ERASE="^H" export ERASE fi stty erase $ERASE trap "echo logout" 0 cat /etc/copyright if [ -r /etc/motd ] then cat /etc/motd fi if [ -f /usr/bin/mail ] then if mail –e then echo "You have mail." fi fi if [ -f /usr/bin/news ] then news –n fi if [ -r /tmp/changetape ] then echo "\007\nYou are the first to log in since backup:" echo "Please change the backup tape.\n" rm -f /tmp/changetape fi fi trap 1 2 3 ###################### The End ########################## |
#!/usr/bin/sh ############# /.profile ################ set +u PATH=/usr/sbin:$PATH:/sbin:/home/root if [ ! "$VUE" ]; then if [ "$TERM" = "" ] then eval ` tset -s -Q -m ':?hp' ` else eval ` tset -s -Q ` fi stty erase "^H" kill "^U" intr "^C" eof "^D" susp "^Z" stty hupcl ixon ixoff tabs echo echo "Value of TERM has been set to \"$TERM\". " export TERM EDITOR=vi export EDITOR fi set –u trap "echo 'logout root'" 0 MAIL=/var/mail/root echo "WARNING: YOU ARE SUPERUSER !!\n" export PS1=`hostname`':$PWD# ' ############################# The End ############################## |
#!/sbin/sh ######################## /sbin/init.d/inetd ####################### PATH=/sbin:/usr/sbin:/usr/bin export PATH rval=0 set_return() { x=$? if [ $x -ne 0 ]; then echo "EXIT CODE: $x" rval=1 # always 1 so that 2 can be used for other reasons fi } case "$1" in start_msg) echo "Start Internet services daemon" ;; stop_msg) echo "Stopping Internet services daemon" ;; 'start') if [ -f /etc/rc.config ]; then . /etc/rc.config else echo "ERROR: /etc/rc.config defaults file MISSING" fi mask=`umask` umask 000 [ -x /usr/sbin/inetd ] && /usr/sbin/inetd $INETD_ARGS if [ $? -eq 0 ]; then echo "Internet Services started" else echo "Unable to start Internet Services" fi umask $mask ;; 'stop') if [ -f /etc/rc.config ]; then . /etc/rc.config else echo "ERROR: /etc/rc.config defaults file MISSING" fi /usr/sbin/inetd -k set_return if [ $rval -eq 0 ]; then echo "Internet Services stopped" else echo "Unable to stop Internet Services" fi ;; *) echo "usage: $0 {start|stop}" rval=1 ;; esac exit $rval ############################ The End ##############################3 |
#!/sbin/sh ############# /sbin/rc ################ arg=$1 arg2=$2 PATH=/sbin export PATH /sbin/stty clocal icanon echo opost onlcr ixon icrnl ignpar 2> /dev/null umask 022 get_scripts() { state=$1 mode=$2 dir=/sbin/rc${state}.d ls $dir 2>/dev/null | while read name do case $name in ${mode}*) path=$dir/$name if [ "$mode" = "S" ]; then desc=`$path start_msg` elif [ "$mode" = "K" ]; then desc=`$path stop_msg` fi echo $path $desc esac done } if [ -f /sbin/rc.utils ]; then . /sbin/rc.utils else init_list() { echo $1 } add_list() { eval $1 } run_list() { : } fi # If /etc/rc.config contains default information (first boot), # /sbin/auto_parms will invoke /sbin/set_parms to remedy the situation. # For 10.0 release, the default HOSTNAME is unset or an empty string. # Assume a timezone if /etc/TIMEZONE does not exist. TZ=EST5EDT if [ -f /etc/rc.config ]; then . /etc/rc.config if [ -x /sbin/auto_parms ]; then /sbin/auto_parms else echo "\nWARNING: /sbin/auto_parms does not exist" echo "DHCP invocation skipped." fi else echo "\nWARNING: /etc/rc.config does not exist" echo "System name not set, default $TZ assumed." fi export TZ # Set runlevel information set `who -r` x new=$7 # new run level old=$9 # previous run level # Check to see if we are run from /etc/inittab, or from the command line. # If run from the command line, set the old run-level to the new run-level. if [ $PPID != 1 ]; then old=$new # If the new run-level was specified on the command line,go to that state # instead. if [[ -n $arg2 ]]; then new=$arg2 fi fi if [ "$new" = S ]; then new=0 tosingle=1 else tosingle=0 fi BOOT=0 if [ "$old" = S ]; then old=0 BOOT=1 fi # Process scripts found=0 if [ "$new" -gt "$old" ]; then # new run level is higher than old, so run start scripts in # all intermediate run levels and in new run level. if [ $BOOT = 1 ]; then init_list "HP-UX Start-up in progress" else init_list "Transition to run-level $new in progress" fi typeset -i lvl=$old lvl=lvl+1 while [ $lvl -le "$new" ]; do get_scripts $lvl S | while read name descrip; do if [ -s "$name" ]; then add_list "$name start" "$descrip" found=1 fi done lvl=lvl+1 done elif [ "$new" -lt "$old" ]; then # new run level is lower than old level, so run kill scripts # in all intermediate levels and in new level. if [ "$new" = 0 ]; then init_list "System shutdown in progress" else init_list "Transition to run-level $new in progress" fi typeset -i lvl=$old lvl=lvl-1 while [ $lvl -ge "$new" ]; do get_scripts $lvl K | while read name descrip; do if [ -s "$name" ]; then add_list "$name stop" "$descrip" found=1 fi done lvl=lvl-1 done # If we're ending up in state 0 or S, run the start scripts for # that state. if [ "$new" = 0 ]; then get_scripts 0 S | while read name descrip; do if [ -s "$name" ]; then add_list "$name start" "$descrip" found=1 fi done fi else # old and new run levels are the same. Assume that execution # is from the command line and run start scripts for the current # run level init_list "Starting subsystems for run-level $new" get_scripts ${new} S | while read name descrip; do if [ -s "$name" ]; then add_list "$name start" "$descrip" found=1 fi done fi if [ $found = 1 ]; then if [ "$BOOT" = 1 ]; then run_list boot else run_list fi fi if [ "$new" = 0 ]; then case $arg in "shutdown") exec /sbin/sh ;; "reboot") /sbin/reboot ;; "off") /sbin/reboot -h ;; esac #If transitioned to real state 0 (that is, not state S) via init, halt. if [[ $PPID -eq 1 && "$tosingle" -ne 1 ]]; then /sbin/reboot -h fi fi # Output message to indicate completion echo if [ $BOOT = 1 ]; then echo "The system is ready." else echo "Transition to run-level $new is complete." fi ############################## The End #################################3 |
#!/sbin/sh ##################### /sbin/init.d/net ########################## # # net: configure lan interface(s) at initialization time. # /etc/rc.config.d/netconf defines the configuration parameters: # # INTERFACE_NAME[i]: network interface name (e.g., lan0) # IP_ADDRESS[i]: IP address of your system in decimal dot format # SUBNET_NETMASK[i]: subnetwork mask in decimal dot format # BROADCAST_ADDRESS[i]: broadcast address (other than default) in decimal # format # LANCONFIG_ARGS[i]: lanconfig(1m) options (e.g., ieee, ether) # LOOPBACK_ADDRESS: loopback address (always 127.0.0.1) # # ROUTE_DESTINATION[i]: route destination # ROUTE_MASK[i]: subnet mask # ROUTE_GATEWAY[i]: local or remote IP address of gateway # ROUTE_COUNT[i]: zero for local gateway, one for remote gateway # ROUTE_ARGS[i]: route command options and arguments # ########################################################################### set +u export PATH=/sbin:/usr/sbin:$PATH NETCONF=/etc/rc.config.d/netconf NETSTAT_DATA=/var/adm/netstat_data OKAY=0 ERROR=1 WARNING=2 # $1 = name of array # return highest array element index in env; return -1 if no elements function maxindex { # find only lines that start with "var[...]=", grab only the number # between "[...]", and print only the last one. # we would like to use `sed` as follows: # typeset i=$(set | sed -n 's/^'$1'\[\([[:digit:]]\{1,\}\)\]=.*$/\1/p' # | tail -1) # but it is not guaranteed to be in a mounted file system at this time. typeset line typeset i=-1 set | while read line; do # strip "var[" and "]=...", leaving only number between "[...]" line=${line#*$1\[} line=${line%%\]=*} # if line is all digits, we found "var[...]=...", # and line is string between "[...]" if [[ -n $line && -z ${line##*([[:digit:]])} ]]; then i=$line fi done print -- $i return 0 } ########## # main # ########## case $1 in start_msg) print "Configure LAN interfaces" exit $OKAY ;; stop_msg) print "Unconfigure LAN interfaces" exit $OKAY ;; stop) exit $OKAY ;; start) ;; # fall through *) print "USAGE: $0 {start_msg | stop_msg | start | stop}" >&2 exit $ERROR ;; esac ########### # start # ########### # Remove the existing /var/adm/netstat_data file. The first time # netstat is executed, a new /var/adm/netstat_data file will be # created. rm -f $NETSTAT_DATA # Get actual configuration if [[ -f $NETCONF ]]; then . $NETCONF # display any errors if (($? != 0)); then # NB: this is not working as expected: status is not propagated! print "ERROR: Incorrect data in the file $NETCONF." >&2 exit $ERROR fi else print "ERROR: Missing the file $NETCONF." >&2 exit $ERROR fi rval=$OKAY # Do ifconfig and lanconfig commands for each interface # `foo=$(print $foo)` collapses whitespace, remove surrounding whitespace # We can have __fewer__ IP_ADDRESSes than INTERFACE_NAMEs (interfaces to be # ignore). We can also have __fewer__ SUBNET_MASKs, BROADCAST_ADDRESSes and # LANCONFIG_ARGS (defaulted). But we cannot have __more__. # sanity check nIF=$(maxindex INTERFACE_NAME) if (($(maxindex IP_ADDRESS) > nIF)) || \ (($(maxindex SUBNET_MASK) > nIF)) || \ (($(maxindex BROADCAST_ADDRESS) > nIF)) || \ (($(maxindex LANCONFIG_ARGS) > nIF)) then print "WARNING: Missing INTERFACE_NAME for corresponding IP_ADDRESS, SUBNET_MASK," >&2 print " BROADCAST_ADDRESS or LANCONFIG_ARGS in the file" >&2 print " $NETCONF. Excess variables will be ignored." >&2 rval=$WARNING fi i=0 while ((i <= nIF)); do NAME=$(print ${INTERFACE_NAME[i]}) INTERFACE_NAME[i]=$NAME # without whitespace for route tests below IP=$(print ${IP_ADDRESS[i]}) IP_ADDRESS[i]=$IP # without whitespace for route tests below if [[ $IP = "RARP" ]]; then IP=`/usr/sbin/rarpc $NAME` IP_ADDRESS[i]=$IP # without whitespace for route tests below fi if [[ -n $NAME && -n $IP ]]; then MASK=$(print ${SUBNET_MASK[i]}) [[ -n "$MASK" ]] && MASK="netmask $MASK" BCAST=$(print ${BROADCAST_ADDRESS[i]}) [[ -n "$BCAST" ]] && BCAST="broadcast $BCAST" PROTO=$(print ${LANCONFIG_ARGS[i]}) # do not set PROTO to any default emsg=$(ifconfig $NAME $IP $MASK $BCAST up 2>&1) status=$? if ((status == 0)) && [[ -n $PROTO ]] ; then emsg=$(lanconfig $NAME $PROTO 2>&1) status=$? fi if ((status != 0)); then print "ERROR: $NAME interface: $emsg" >&2 rval=$ERROR fi fi let i=i+1 done IP=$(print $LOOPBACK_ADDRESS) if [[ -n $IP ]]; then emsg=$(ifconfig lo0 $IP up 2>&1) if (($? != 0)); then print "ERROR: lo0 interface: $emsg" >&2 rval=$ERROR fi else print "ERROR: Missing LOOPBACK_ADDRESS in the file $NETCONF." >&2 print " lo0 interface not initialized." >&2 rval=$ERROR fi # Do route command for each configured route # Note: ${IP_ADDRESS[i]} must have whitespace removed already (above) # We must have the __same__ number of ROUTE_GATEWAYs as ROUTE_DESTINATIONs. # But we can have __fewer__ ROUTE_COUNTs and ROUTE_MASKs (defaulted). n=$(maxindex ROUTE_DESTINATION) if (($(maxindex ROUTE_GATEWAY) != n)) || \ (($(maxindex ROUTE_COUNT) > n)) then print \ "WARNING: Missing ROUTE_DESTINATION for corresponding ROUTE_GATEWAY" >&2 print " or ROUTE_COUNT in the file $NETCONF." >&2 print " Excess variables will be ignored." >&2 rval=$WARNING fi i=0 while ((i <= n)) do DEST=$(print ${ROUTE_DESTINATION[i]}) GWAY=$(print ${ROUTE_GATEWAY[i]}) if [[ -n $DEST && -n $GWAY ]]; then COUNT=$(print ${ROUTE_COUNT[i]}) if [[ -z $COUNT ]]; then # default COUNT: if GWAY is one of the local interface IP # addresses, count is 0; otherwise, count is 1. COUNT=1 k=0 while ((k <= nIF)); do if [[ $GWAY = ${IP_ADDRESS[k]} && -n ${INTERFACE_NAME[k]} ]]; then COUNT=0 break; fi let k=k+1 done fi ARGS=${ROUTE_ARGS[i]} MASK=$(print ${ROUTE_MASK[i]}) if [[ -z $MASK ]]; then # No subnet mask if [[ -z $ARGS ]]; then # No arguments emsg=$(route add $DEST $GWAY $COUNT 2>&1) else # With arguments emsg=$(route $ARGS add $DEST $GWAY $COUNT 2>&1) fi else # Subnet mask has been entered. if [[ -z $ARGS ]]; then # No arguments emsg=$(route add $DEST netmask $MASK $GWAY $COUNT 2>&1) else # With arguments emsg=$(route $ARGS add $DEST netmask $MASK $GWAY $COUNT 2>&1) fi fi # ignore "entry in use" errors. these can arise because we # booted via NFS diskless, which added routes already if (($? != 0)) && [[ -n ${emsg##*entry in use*} ]]; then print "ERROR: $emsg" >&2 rval=$ERROR fi fi let i=i+1 done # add loopback route for local interfaces to improve performance k=0 while ((k <= nIF)) do if [[ -n ${IP_ADDRESS[k]} && -n ${INTERFACE_NAME[k]} ]]; then emsg=$(route add ${IP_ADDRESS[k]} $LOOPBACK_ADDRESS 0 2>&1) if (($? != 0)) && [[ -n ${emsg##*entry in use*} ]]; then print "ERROR: $emsg" >&2 rval=$ERROR fi fi let k=k+1 done exit $rval ##################### The End ########################### |