星期四, 2月 22, 2007

SH 教學


SH 教學


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

沒有留言: