UNIX Shell本身是一个交谈式的命令环境,也是一个功能强大的译式程式语言(Interpreter)。一般我们称以UNIX Shell 写成的程式为Shell Script。不同的Shell语法,会有一定程度的差异。
Borne Shell(/bin/sh)是UNIX作业系统中最早存在的Shell,在所有的UNIX版本中均可发现他的存在,Borne Shell的语法适合Shell命令程式的写作。
UNIX Shell Script 的内容为UNIX指令与一些控制及回圈指令的组合。
UNIX Shell Scirpt的第一行开头为符号"#!"加上所用Shell名称,其用意为告诉kernel,这是一个可执行的程式,同时执行时的环境为所指定的shell(缺少这一行,执行时可能会遭遇到不可预期的错误)。
Shell Script是一种"Free Format"的程式,除了控制回圈须注意结构完整性外,程式本身并无特殊的格式。下面是一个Borne Shell的例子:
#!/bin/sh
echo " This is a Borne Shell Script "
(为使你的Shell Script可以执行,你必须将这个Shell Script的执行权限"x"打开 : chmod +x shell_script)
关于变数
设定变数方式为
var=value
取用变数的方法为
$var
Exmaple 1:
#!/bin/sh
woody="吴贤明 的小名"
echo $woody
(local)变数的设定,会在在同一个process中持续存在,一直到此process结束。
Shell中,变数的值可以含有space的字串,带有一个以上space的的变数,给定值的时候,必须以成对的双引号( " )或单引号(')涵盖之。
双引号( " )中若含有变数($var),会先将变数转换成其实际的值,单引号(')则会将$var当成是一个值,而不会作转换动作。
Example 2:
1. echo "woody就是 $woody"
2. echo 'woody就是 $woody '
结果:
1.woody 就是 吴贤明 的小名
2.woody 就是 $woody
Borne Shell中的内定变数
变数 变数意义
$# Number of arguments on the command line
$- Shell 的选项
$? Exit value of the last command executed ( in general, 0代表执行无误,1代表指令有误)
$$ Process number of the current process
$n Command line 中的参数,$0代表指令名称,$1代表第一个参数,$2代表第二个参数....
$* Command line 中的所有参数
Example 3:
Shell Script : var_test
#!/bin/sh
echo $#
echo $-
echo $?
echo $$
echo $0
echo $1
echo $2
echo $*
执行 var_test 1 2 3 4 5
结果? (Try it !!)
讯息列印
echo 指令可以让你一次在银幕上列印出一行字串(with Double quote‘"’ or Single quote‘'’),以下的方式可以让你一次印出一段文章:
Example 4:
#!/bin/sh
var1="变数一"
var2="变数二"
cat << SEGMENT1
Strings between the two "SEGMENT1"s will be treated as
constant,and printed out from the monitor。Variables between
these two SEGMENT1's will be calculated before any processing。
Yo umay try the following:
var1=$var1
var2=$var2
SEGMENT1
Another Example:
cat << \SEGMENT2 ##<--请注意这行中的符号‘\’
这是避免变数被解释的方法,请注意义以下字串被列印
出来的结果:
var1=$var1
var2=$var2
SEGMENT2
这个程式执行的结果为:
Strings between the two "SEGMENT1"s will be treated as
constant,and printed out from the monitor。Variables between
these two SEGMENT1's will be calculated before any processing。
Yo umay try the following:
var1=变数一
var2=变数二
Another Example:
这是避免变数被解释的方法,请注意义以下字串被列印
出来的结果:
var1=$var1
var2=$var2
read - 从银幕读入一个变数
Example 5:
#!/bin/sh
echo -e "Please input your name: \c" #(\c迫使游标不换行)
read name
echo "Hello, $name"
if 指令
Borne Shell中,if指令的用法为
if condition
then
command(s)
[elif condition
then command(s)]
[else
command(s)]
fi
中括号([])表示可有可无。
Example 6:
#!/bin/sh
ls -l /etc/host.conf
if [$? -eq 0] 注
then
echo "/etc/host.conf is there !!"
else
echo "/etc/host.conf is not there !!"
fi
注[$var -op value]可以比对$var与value ($var为数值变数)。op的值有gt (greater then),eq(equal to ),lt(less than),ge (greater than or equal to ),ne(not equal)及le(less than or qual to)。
test指令 (or [])
if控制回圈中的condition值只有真(0)与伪(none zero)两种,test指令(or [])提供了判断真与假的功能。
test可提供档名、字串与数值等真与伪的判断
档名
test -options file_name or [-option file_name]
常用option与其所代表的意义如下:
-r
True if file exists and readble
-w
True if file exists and writadble
-x
True if file exists and executadble
-f
True if file exists and is a regular file
-d
True if file exists and is a directory
-u
True if file exists and is setuid
-s
True if file exists and is greater than zero in size
字串 test -option string or [-option string]
常用option与其所代表的意义如下:
-z
True if string length is zero
-n
True if string length is non-zero
test string1 = string2 or [string1 = string2]
* True if string1 is identical to string2
test string1 != string2 or [string1 != string2]
--> True if string1 is not identical to string2
数值 test n1 -op n2 or [n1 -op n2]
常用op(运算元)与其所代表的意义如下
-eq
True if n1and n2 are equal
-ne
True if n1and n2 are not equal
-gt
True if n1 is greater than n2
-ge
True if n1 is greater than or equal tp n2
-lt
True if n1 is less than n2
-le
True if n1 is less than or equal to n2
** Both n1 & n2 are intergers
Case 指令(Conditional Swith)
case 指令的语法
case variable in
pattern1[|pattern1a]) commands ;;
pattern2) commands;;
....
*) commands ;;
esac
Example 7:
#!/bin/sh
cat << EOF
****************************************
a.I need a banana.
b.I need an orange.
c.I need an apple.
****************************************
EOF
read choice
case $choice in
a|A) echo "You need a banana !!" ;;
b|B) echo "You need an orange !!" ;;
c|C) echo "You need an apple !!" ;;
*) echo "Bad choice, see yo next time !!";;
esac
while 指令
while 指令语法
while condition
do
commands
done
##回圈中commands会一直被重复执行直到condition 的值为伪为止。
Example 8:计算从1加到10并把结果印出
#!/bin/sh
NO=11
START=1
SUM=0
while [ $NO -gt 0 ]
do
SUM=****expr $START + $SUM****
START=****expr $START + 1****
NO=****expr $NO - 1****
done
echo "The answer is $SUM"
说明:
1. Shell中把所有变数均当成字串,因此进行整数运算时,必须特别注明。内建function "expr"可以帮我们进行这样的数值计算。
2. 符号 **** 代表在变数给定的运算式中,带有指令或函数。设定变数必须先行运算,再做设定。例如
HOSTNAME=****/bin/hostname****
则$HOSTNAME的值会是指令/bin/hostname执行的结果
until 指令
until 指令语法
until condition
do
commands
done
##until指令用法与while恰巧相反;回圈中commands会一直被重复执行直
到condition 的值为真。
请试著以until重写上面数字累加的例子。
trap - Trapping Signal
Signal 是UNIX系统中用来传递控制讯息(由一程序到另一程序)的一种机制。
一个Process收到signal之后,会优先处理(将控制权交出),处理完毕之后在行返回元程序继续执行(重新取回控制权)。
Signal为一非同步讯息,由数字所构成。不同的数字所代表不同的控制讯息及不同的处理步骤,例如signal "2" (按下Ctrl+C"会送出这个讯号)代表结束目前程序。Programmer也可以在程式撰写时,重新定义Signal。‘trap’是在bash环境下,可供程式撰写者重设SIgnal的工具。
利用shell programming撰写程式时,使用trap通常是希望能够避免使用者以不正常方式中断程式,而使程式进入一个不可知的状态,危害到系统运作,或取得不正当的存取权限。UNIX Signal种类,及所代表的意义,请参考讲义‘UNIX Process’。常用的HotKey与Signal的对应如下:
Ctrl+C 2
Ctrl+\ 3
Ctrl+Z 20
trap格式
trap 'commands; command' signal_number
当程序收到"signal_number"时,会屏除系统预设处理步骤,改以执行单引号中的指令代之。
Example:
trap 'echo "Why You Use Ctrl+C ? Don't Do That Again !!!" 1
如果你在shell script中(程式最上头)加上这行指令,则当使用者(这执行这个程式时)按下Ctrl+C(预设动作为结束程式),银幕上会印出"Why You Use Ctrl+C ? Don't Do That Again !!!",并继续程式的执行。
Example :9 以下的例子是一个交谈式的新帐号建立程式
#!/bin/sh
ID=****whoami****
if [ $ID != "root" ]
then
cat << SEGMENT1
***********************************************
你不是系统管理者!!
这个程式以交谈式方式帮你建立使用者帐号,
你必须具备SuperUser权限。
***********************************************
SEGMENT1
exit 1
fi
echo -e "\n\n请输入使用者帐号:\c"
read login
echo -e "\n请输入使用者姓名:\c"
read comment
echo -e "请输入使用者密码(你将看不到你的输入):\c"
password=****./inp****
# "inp"是Woody老师写的一只小小程式,功能在避免
# 使用者key-in文字在银幕Show出,Source请参见nmc anonymous
# ftp linux目录下的inp.c,Compile with " cc -o inp inp.c "
echo -e "请再输入一次:\c"
password1=****./inp****
if [ $password != $password1 ]
then
echo "两次输入密码不一致,请再试一次"
exit 1
fi
adduser -c $comment $login
if [ $? -eq 0 ]
then
echo "Account $login Created !"
echo "$login:$password"|chpasswd
#chpasswd是系统指令,读入"username:password" Pair(From File),将帐号"username"的密码改成"password"
else
echo "Account Not Created !! "
fi
echo"";echo ""
Example :10 以下的例子是一个交谈式的使用者帐号密码更改程式(This Program is for root only!)
#!/bin/sh
trap "" 2 3 20
echo -e "\n\n\n"
if [ ! -x /usr/sbin/inp ]
then
echo -e "/usr/sbin/inp Needed, Please CHECK IT OUT !!!\n\n\n"
exit 1
fi
echo -e "请输入你要更改密码的帐号: \c"
LOGNAME=****whoami****
read login
if [ $LOGNAME != "root" ]
then
echo "You are Not Authorized to change OTHER'S Passwprd ...!"
exit 1
fi
grep ^$login":" /etc/passwd > /dev/null
if [ $? -eq 0 ]
then
echo -e "You New Password ....:\c"
passwd=****/usr/sbin/inp****
echo -e "You New Password Again....:\c"
passwdagain=****/usr/sbin/inp****
if [ $passwd = $passwdagain ]
then
echo "$login":"$passwd" | /usr/sbin/chpasswd
if [ $? -eq 0 ]
then
echo "Passwdord For $login Changed !"
else
echo "Password Not Changed, Please Try again !"
fi
else
echo "Password Not Match, Please Try Again.."
fi
else
echo "User Not Exist, Please Check it OUt !"
fi
echo -e "\n\n\n"
Exercise:
1. 请将讲义Example 1~ 8亲自做一次,并确实了解其语意(Know HOW)。
2. token=super
请问下面指令会得到什么结果?你知道为何如此吗?
echo $tokenman
echo '$token'man
echo "$token"man
3. 请写一shell script
(1).提示使用者选择1.可连(telnet)至ccsun, 2.可连(telnet)至bbs, 3. 可连(telnet)至nmc.nchu.edu.tw
(2).从键盘(keyboard)读取变数‘Choice’
(3).IF Choice=1 --> telnet to ccsun
IF Choice=2 --> telnet to bbs
IF Cjoice=3 --> telent to nmc.nchu.edu.tw
Otherwise Say something to user, and terminate the program
4. 请重新改写Example 8 with command "until" !
5. 请写一个shell script:
(1).提示使用者输入username
(2).若此user存在,输出‘此使用者存在,请输入下一笔资料’
(3).若此user不存在,输出‘此使用者不存在,请重新输入’
(4).若输入为Esc键,则跳离此一程式。
提示:
(1).grep username /etc/passwd可检查该user是否存在。
(2).echo $?可以检查上一个指令是否执行成功。
(3).输入特殊符号(或Hot Key)的方式为^v + Hot-key
|