1. 一個簡單的例子 #!/bin/sh echo "** Non-root UID=0 or GID=0 accounts:" grep ':00*:' /etc/passwd | \ awk -F: 'BEGIN {n=0} $1 != "root" {print $0 ; n=1} END {if (n==0) print "None found."}' --------------------------------------------------------------------- 2. shift 的用法,及一些特殊符號的意義 #!/bin/sh echo $1 $2 $3 echo $# # will be 4 shift echo $1 $2 $3 echo $# # will be 3 # "$*" = "$1 $2 $3....$n" echo $* # "$@" = "$1" "$2" "$3" "$4" ..."$n" echo $@ # # $? Exit status of previous command # $$ PID of this shell's process # $! PID of the most recently started backgroup job echo $? echo $$ echo $! --------------------------------------------------------------------- 3. 變數設定的方法,及特殊設定 #!/bin/sh item=aaaa item1=bbbb echo ${item}1 $item1 #!/bin/sh name=rache1 echo ${name-tatiana} # show rache1 echo ${name2-tatiana} # show tatiana echo ${name=tatiana} # show rache1 echo ${name2=tatiana}; echo $name2 # show tatiana # tatiana dir=${name5-`pwd`}; echo $dir --------------------------------------------------------------------- 4. if 的用法,有很多比較方法 -s, -r, -f, -d .. 請看 man if or man test 例如:底下兩敘述是相同的 if test -z "$var"; then ... if [ -z "$var" ]; then ... #!/bin/sh # in sh , echo -n 只有當 /usr/ucb 路徑在 /usr/bin 之前才有用 if [ -f /usr/bin/ls ]; then echo -n " ls command found " fi #!/bin/sh strings /vmunix | grep UNIX > /tmp/motd head -1 /etc/motd | grep UNIX > /tmp/th if [ -z /tmp/th ] then cat /etc/motd >> /tmp/motd else tail +2 /etc/motd >> /tmp/motd fi mv /tmp/motd /etc/motd --------------------------------------------------------------------- 5. 再看一個加上變化的 if #!/bin/sh set `who -r` if [ $9 = "S" ]; then echo "The system is coming up. Be patient." elif [ $7 = "2" ]; then echo "Changing to state 2." else echo "Changing to state 3." fi 底下是更多的 if 的例子 if [ $9 = "S" ] if [ -s /etc/ptmp ] if [$# -lt 4 ] if [ ! -f /etc/.fscksk ] if [ $? -eq 0 ] if [ $? -ne 0 ] if test -z "$var" if [ -z "$var" ] --------------------------------------------------------------------- 6. 還是 if 的例子 #!/bin/sh pid=`/bin/ps -e | grep 'lpsched$' | sed -e 's/^ *//' -e 's/ .*//'` echo ${pid} if [ "${pid}" != "" ] then echo $pid /bin/kill ${pid} fi if [ -r /fastboot ]; then echo "skip the fsck" else echo "do the fsck" fi if [ -d /etc/rc0.d ] then echo "run the K files" fi if [ -x /etc/inetd ] then echo "inetd" fi if [ "${BOOT}" = "yes" -a -d /etc/rc0.d ] then echo "run /etc/rc0.d" fi --------------------------------------------------------------------- 7. while 的語法,與讀進參數 #!/bin/sh cat /etc/vfstab | while read DEVICE MOUNT_DIR READONLY FS DUMMY1 DUMMY2 do echo "$DEVICE, $MOUNT_DIR, $READONLY, $FS, $DUMMY1, $DUMMY2" done --------------------------------------------------------------------- 8. case 的用法,和 csh 真的差很多 $? 是執行命令後的 return status , 0: succeed , 1: false #!/bin/sh #/etc/fsck -p > /dev/console ls / > /dev/null case $? in 0) echo "return 0" ;; 2) exit 1 ;; 4) echo "return 4" ;; *) echo "Unknown error in reboot" > /dev/console exit 1 ;; esac --------------------------------------------------------------------- 9. 再一個 case 的範例 # can get the same result when "$1" or $1 #case $1 in case "$1" in 'start') echo "start" ;; 'stop') echo "stop" ;; '-abc') echo "-abc option" ;; '-h'|'-help') echo "help option" ;; *) echo "usage: $0 {start|stop}" ;; esac echo "--------------------------------------------" shell=tcsh case $shell in *csh) echo "C-shell style shells are not acceptable" ;; *zsh) echo " zsh is not acceptable" ;; esac --------------------------------------------------------------------- 10. 一個 for 的簡單例子 #!/bin/sh for d in /tmp /usr/tmp /tmp/tmp ; do echo $d done --------------------------------------------------------------------- 11. 同樣的 for , 以 *.sh 代替 for file in *.sh ; do wc -l $file done --------------------------------------------------------------------- 12. 取得使用者回答的範例 echo "fsck all disks? [y] \c" read ans #echo $ans if [ $ans = 'y' -o $ans = 'Y' ] ; then echo "Yes" else echo "no.." fi --------------------------------------------------------------------- 13. 迴圈 while ,這個例子會印出 1 2 3 4 5 #!/bin/sh i=1 while [ $i -le 5 ]; do echo -n $i i=`expr $i + 1` done --------------------------------------------------------------------- 14. 一個字串連結的例子 $a$b$c = cmd , 又 cmd = date #!/bin/sh a=c; b=m; c=d; cmd=date eval $`echo $a$b$c` --------------------------------------------------------------------- 15. 這個例子會列出目前目錄下的子目錄名稱 #!/bin/sh # usage: process sub-directory dir=`pwd` for i in *; do if [ -d $dir/$i ] #if test -d $dir/$i then cd $dir/$i # while (echo -n "$i: (waiting command:) ") ; read x; do # eval $x # done echo $i cd .. fi done --------------------------------------------------------------------- 16. 更改檔名 *.html -> *.htm #!/bin/sh for i in *.html ; do echo $i mv $i `basename $i .html`.htm done ---------------------------------------------------------------------- 17. 更改檔名 *.htm -> *.html #!/bin/sh for i in *.htm ; do echo $i mv $i `basename $i .htm`.html done ---------------------------------------------------------------------- 18. 一個抓下來的片段 while [ $# != 0 ] do case $1 in -v) doversion=1;; -B) BASEDIR=$2; shift;; -l) LOGDIR=$2; shift;; -w) WORKDIR=$2; shift;; -b) BINDIR=$2; shift;; -c) RCFILE=$2; shift;; -e) EXPLAINREPORT=I;; -E) EXPLAINREPORT=Y;; -S) SERVERCHECK=Y;; -O) OS=$2; shift;; -A) ARCH=$2; shift;; -R) REV=$2; shift;; -t) Tiger_TESTMODE=Y;; *) echo "--ERROR-- [con006e] Unknown option $1";; esac shift; done ---------------------------------------------------------------------- 19. 一個實際設定 Solaris 2.x Ftp server 的 shell script #!/bin/sh # script to setup SunOS 5.3 anonymous ftp area # #set OS_VERSION = `uname -r` # handle the optional command line argument case $# in # the default location for the anon ftp comes from the passwd file 0) ftphome="`grep '^ftp:' /etc/passwd | cut -d: -f6`" ;; 1) if [ "$1" = "start" ]; then ftphome="`grep '^ftp:' /etc/passwd | cut -d: -f6`" else ftphome=$1 fi ;; *) echo "Usage: $0 [anon-ftp-root]" exit 1 ;; esac if [ -z "${ftphome}" ]; then echo "$0: ftphome must be non-null" exit 2 fi # This script assumes that ftphome is neither / nor /usr so ... if [ "${ftphome}" = "/" -o "${ftphome}" = "/usr" ]; then echo "$0: ftphome must not be / or /usr" exit 2 fi # If ftphome does not exist but parent does, create ftphome if [ ! -d ${ftphome} ]; then # lack of -p below is intentional mkdir ${ftphome} fi echo Setting up anonymous ftp area ${ftphome} for SunOS `uname -r` #echo Setting up anonymous ftp area ${ftphome} for SunOS $OS_VERSION # Ensure that the /usr/bin directory exists if [ ! -d ${ftphome}/usr/bin ]; then mkdir -p ${ftphome}/usr/bin fi cp /usr/bin/ls ${ftphome}/usr/bin chmod 111 ${ftphome}/usr/bin/ls # Now set the ownership and modes to match the man page chown root ${ftphome}/usr/bin chmod 555 ${ftphome}/usr/bin # this may not be the right thing to do # but we need the bin -> usr/bin link if [ -r ${ftphome}/bin ]; then mv -f ${ftphome}/bin ${ftphome}/Obin fi ln -s usr/bin ${ftphome} # Ensure that the /usr/lib and /etc directories exist if [ ! -d ${ftphome}/usr/lib ]; then mkdir -p ${ftphome}/usr/lib fi if [ ! -d ${ftphome}/etc ]; then mkdir -p ${ftphome}/etc fi #Most of the following are needed for basic operation, except #for libnsl.so, nss_nis.so, libsocket.so, and straddr.so which are #needed to resolve NIS names. cp /usr/lib/ld.so /usr/lib/ld.so.1 ${ftphome}/usr/lib for lib in libc libdl libintl libw libnsl libsocket \ nss_nis nss_nisplus nss_dns nss_files do cp /usr/lib/${lib}.so.1 ${ftphome}/usr/lib rm -f ${ftphome}/usr/lib/${lib}.so ln -s ./${lib}.so.1 ${ftphome}/usr/lib/${lib}.so done cp /usr/lib/straddr.so.2 ${ftphome}/usr/lib rm -f ${ftphome}/usr/lib/straddr.so ln -s ./straddr.so.2 ${ftphome}/usr/lib/straddr.so cp /etc/passwd /etc/group /etc/netconfig ${ftphome}/etc chmod 555 ${ftphome}/usr/lib/* chmod 444 ${ftphome}/etc/* # Now set the ownership and modes chown root ${ftphome}/usr/lib ${ftphome}/etc chmod 555 ${ftphome}/usr/lib ${ftphome}/etc # Ensure that the /dev directory exists if [ ! -d ${ftphome}/dev ]; then mkdir -p ${ftphome}/dev fi # make device nodes. ticotsord and udp are necessary for # 'ls' to resolve NIS names. prefix="/devices/pseudo/mm@0:" for device in zero do line=`ls -l ${prefix}${device} | sed -e 's/,//'` major=`echo $line | awk '{print $5}'` minor=`echo $line | awk '{print $6}'` rm -f ${ftphome}/dev/${device} mknod ${ftphome}/dev/${device} c ${major} ${minor} done prefix="/devices/pseudo/clone@0:" for device in tcp udp ticotsord do line=`ls -l ${prefix}${device} | sed -e 's/,//'` major=`echo $line | awk '{print $5}'` minor=`echo $line | awk '{print $6}'` rm -f ${ftphome}/dev/${device} mknod ${ftphome}/dev/${device} c ${major} ${minor} done chmod 666 ${ftphome}/dev/* ## Now set the ownership and modes chown root ${ftphome}/dev chmod 555 ${ftphome}/dev if [ ! -d ${ftphome}/pub ]; then mkdir -p ${ftphome}/pub fi chown ftp ${ftphome}/pub chmod 777 ${ftphome}/pub ---------------------------------------------------------------------- 20. eval 和 exec 的不同 eval 只是去執行後面的命令,但是 exec 會執行該命令後跳出 shell 看例子就知道 #!/bin/sh echo "Input command : \n" read cmd eval $cmd # 底下會執行 echo "You can see this line ..after executing $cmd" #!/bin/sh echo "Input command : \n" read cmd exec $cmd # 底下不會執行 echo "You can not see this line ..after executing $cmd" ---------------------------------------------------------------------- 21. 字串連接, 如下,最後會印出 /etc/yp yproot_dir=/etc def_dom=yp domain_dir="$yproot_dir""/""$def_dom" echo $domain_dir ---------------------------------------------------------------------- 22. case , if , function 綜合用法 #!/bin/sh killproc() { # kill the named process(es) pid=`ps -e | grep $1 | sed -e 's/^ *//' -e 's/ .*//'` # 請特別注意 $pid 和 "$pid" 居然不同,我也不懂 #if [ $pid = "" ]; then if [ "$pid" = "" ]; then echo "Can't find process \"$1\" "; exit 2 fi echo "kill the process \"$1\" with PID $pid"; kill $pid 2> /dev/null } case $# in 1) killproc $1 ;; *) echo "usage: $0 daemon-name" ;; esac ---------------------------------------------------------------------- 23. 將大寫檔名改成小寫檔名 tr string1 string2 會將 standard input內所對應到的 string1 都以 string2 取代 for file in *; do mv $file `echo $file | tr '[A-Z]' '[a-z]'` done 加上一點變化,只處理大寫的檔名,不過執行過後,第二次會有問題,還不是很懂 for file in [A-Z]*; do echo "process $file" mv $file `echo $file | tr '[A-Z]' '[a-z]'` done ---------------------------------------------------------------------- 24. case 的變化,一個轉換西元到民國的範例 [0-9][0-9] 表示有兩個存在的數, [0-9][0-9][0-9][0-9] 表示有四個存在的數 當然也可以 [a-Z] [a-A]等等的變化了 不懂的地方是 echo 1>&2 這個敘述 echo "Input year : \c" read year case "$year" in [0-9][0-9]) year=19${year} years=`expr $year - 1911` ;; [0-9][0-9][0-9][0-9]) years=`expr $year - 1911` ;; *) echo 1>&2 Year \"$year\" out of range ... exit 127 ;; esac echo "$year 是民國 $years" ---------------------------------------------------------------------- 25. if 內有兩個判斷式的寫法 echo "Input year : \c" read year if [ $year -lt 1901 -o $year -gt 2099 ]; then echo 1>&2 Year \"$year\" out of range exit 127 fi ---------------------------------------------------------------------- 26. 處理一些多選一的字元 read next case "$next" in *[A-Za-z]*) echo "a-z A-Z" ;; *[0-9]*) echo "0-9" ;; *) echo "others.." esac ---------------------------------------------------------------------- 27. 7-Apr, 2003 新增 #!/bin/sh # absolutly path condition if [ -z `echo $1 | awk -F / {'print $1'}` ]; then if [ -x $1 ]; then echo "Yes, $1 is executable" fi # others else for foo in `echo $PATH | sed -e 's/:/ /g'` ; do # echo "searching $foo directory" if [ -x $foo/$1 ]; then echo "--> $foo/$1 is executable" exit fi done fi