Shell 编程 第10天

一个简单的 shell 程序
#!/bin/sh
#This is to show what a example looks like.
echo “Our first example”
echo # This inserts an empty line in output.
echo “We are currently in the following directory.”
/bin/pwd
echo
echo “This directory contains the following files”
/bin/ls
前面例子的结构:
1.#!指定执行脚本的 shell
2.#注释行,执行时被忽略。
3.命令和控制结构
创建 shell 程序的步骤:
第一步:创建一个包含命令和控制结构的文件。
第二步:修改这个文件的权限使它可以执行。
使用 chmod u+x
第三步:执行./example
(也可以使用“sh example”执行)
Shell 变量
变量:是 shell 传递数据的一种方法,用来代表每个取值的符号名。
Shell 有两类变量:临时变量和永久变量。
临时变量是 shell 程序内部定义的,其使用范围仅限于定义它的程序,对其它程序不可见。
包括:用户自定义变量、位置变量。永久变量是环境变量,其值不随 shell 脚本的执行结束
而消失。
用户自定义变量
用户定义的变量由字母或下划线开头,由字母、数字或下划线序列组成,并且大小写字母意
义不同。变量名长度没有限制。
在使用变量值时,要在变量名前加上前缀“$”

设置和使用变量
设置变量:
习惯上用大写字母来命名变量。
变量名只能以字母表中的字符开头,
不能用数字。
变量赋值:赋值号“=”两边应没有空格。
定义时赋值,如 ABC=abcdefg
将一个命令的执行结果赋给变量,如:A=`date`
将一个变量赋给另一个变量,如:A=$B
使用 echo 命令用于查看一个变量值。例如:echo$A
列出所有的变量:
#set
[root@helen test]# set | grep PS1
PS1=’[\u@\h \W]\$ ‘
[root@helen test]# PS1=’\$’
#PS1=’\W’
testPS1=’[\W]‘\$
[test]$PS1=’[\W]\$’
[test]#
包含多个字的变量:
$NAME=Mike Ron
运行时出错,应改为:
$NAME=“Mike Ron”或$NAME=‘Mike Ron’
单引号和双引号的区别:
#$ABC=‘$NAME Junior’
#echo$ABC
$NAME Junior
单引号之间的内容原封不动地指定给了变量。
删除变量:
#unset NAME
[test]# $NAME=`date`
-bash: =2011 年: command not found
[test]# NAME=`date`
[test]# echo $NAME
2011 年 02 月 25 日 星期五 03:30:17 CST
[test]# ABC=”$NAME Junior”
[test]# echo $ABC
2011 年 02 月 25 日 星期五 03:30:17 CST Junior
[test]# unset NAME
[test]# echo $NAME
[test]#
简单 Shell 脚本
[test]# vi checkdisk.sh
#!/bin/sh
#Shell Script filename:checkdisk.sh
echo “home directory message” >> /var/log/du.log
/usr/bin/du -sh /home >> /var/log/du.log
/bin/mail -s “Disk Usage Ratio” root < /var/log/du.log
作用:检查指定目录的磁盘空间使用率,将
结果记录在/var/log/du.log,发给 root。
[test]# sh checkdisk.sh
[test]# mail
Mail version 8.1 6/6/93. Type ? for help.
“/var/spool/mail/root”: 1 message 1 new
>N 1 root@localhost.local Fri Feb 25 03:35 21/737 “Disk Usage Rati”
位置变量和特殊变量
Shell 解释执行用户的命令时,将命令行的第一个字作为命令名,而其它字作为参数。
由出现在命令行上的位置确定的参数称为位置参数。
例如:
ls-l file1 file2 file3
$0 这个程序的文件名 ls-l
$n 这个程序的第 n 个参数值,n=1-9
[test]# vi test
#!/bin/sh
echo ‘$0 is: ‘ $0
echo ‘$1 is: ‘ $1
echo ‘$2 is: ‘ $2
“test” 4L, 64C written
[test]# sh test /etc/inittab /etc/fstab
$0 is: test
$1 is: /etc/inittab
$2 is: /etc/fstab
[test]#
有些变量是一开始执行 Script 时就会设定,且不能被修改,但我们不叫它只读的系统
变量,而叫它特殊变量。这些变量当一执行程序时就有了,用户无法将一般的系统变量设定
成只读的。以下是一些等殊变量:
$*这个程序的所有参数
$#这个程序的参数个数
$$这个程序的 PID
$!执行上一个后台指令的 PID

$?执行上一个指令的返回值
[test]# sh special.var file01 file 02
$0 is: special.var
$1 is: file01
$2 is: file
$* is: file01 file 02
$# is: 3
$$ is: 2507
$! is:
$? is: 0
Shell 命令
read 命令
从键盘读入数据,赋给变量
如:read var1 var2
[test]# vi read
#!/bin/sh
read first second third
echo “the first parameter is $first”
echo “the second parameter is $second”
echo “the third parameter is $third”
“read” [New] 5L, 147C written
[test]# sh read
hello good morning
the first parameter is hello
the second parameter is good
the third parameter is morning
[test]#
expr 命令
Shell 变量的算术运算:
expr 命令:对整数型变量进行算术运算
例如:expr 3 + 5
expr $var1 – 5
expr $var1 / $var2
expr $var3 \*1 0
[test]# vi expr
#!/bin/sh
a=10
b=20
c=30
value1=`expr $a + $b + $c`
echo “The value of value1 is $value1″
value2=`expr $c / $b`
echo “The value of value2 of is $value2″
value3=`expr $c \* $b`
echo “The value of value3 of is $value3″
value4=`expr $a + $c / $b`
echo “The value of value4 is $value4″
“expr” 12L, 282C written
[test]# sh expr
The value of value1 is 60
The value of value2 of is 1
The value of value3 of is 600
The value of value4 is 11
[test]#
复杂的 expr 命令
复杂的运算:
expr`expr 5 + 7`/$var4
将运算结果赋予变量:
var4=`expr $var1 / $var2`
[test]# vi test
1 #!/bin/sh
2 var4=2
3 var4=`expr \`expr 5 + 7\` / $var4`
4 echo $var4
“test” 4L, 63C written
[test]# sh test
6
变量测试语句
变量测试语句:用于测试变量是否相等、是否为空、文件类型等。
格式:
test 测试条件
测试范围:整数、字符串、文件
字符串测试:
test str1=str2 测试字符串是否相等
test str1!=str2 测试字符串是否不相等
test str1 测试字符串是否不为空
test -n str1 测试字符串是否不为空
test -z str1 测试字符串是否为空
整数测试:
test int1 -eq int2 测试整数是否相等
test int1 -ge int2 测试 int1 是否>=int2
test int1 -gt int2 测试 int1 是否>int2
test int1 -le int2 测试 int1 是否<=int2
test int1 -lt int2 测试 int1 是否<int2
test int1 -ne int2 测试整数是否不相等
文件测试:
test -d file 指定文件是否目录
test -f file 指定文件是否常规文件
test -x file 指定文件是否可执行
test -r file 指定文件是否可读
test -w file 指定文件是否可写
test -a file 指定文件是否存在
test -s file 文件的大小是否非 0
变量测试语句一般不单独使用,一般做为 if 语句的测试条件,如:
if test -d $1 then

fi
变量测试语句可用[]进行简化,如
test -d $1 等价于[ -d $1 ]
[test]# vi test
1 #!/bin/sh
2 if [ $# -ne 2 ];then
3 echo “Not enough parameters”
4 exit 0
5 fi
6 if [ $1 -eq $2 ];then
7 echo “$1 equals $2″
8 elif [ $1 -lt $2 ];then
9
echo “$1 littler than $2″
10 elif [ $1 -gt $2 ];then
11 echo “$1 greater than $2″
12 fi
“test” 12L, 228C written
[test]# sh test 34 34

34 equals 34
[test]# sh test
34 littler than
[test]# sh test
54 greater than
34 39
39
54 34
34
流控制语句
流控制语句:用于控制 shell 程序的流程 exit 语句:退出程序执行,并返回一个返回码,
返回码为 0 表示正常退出,非 0 表示非正常退出。
例如:exit 0
if…then…fi 语句,例如:
if[-x /etc/init.d/cron]
then
/etc/init.d/cron start
fi
更复杂的 if 语句:
if 条件 1 then
命令 1
elif 条件 2 then
命令 2
else
命令 3
fi
多个条件的联合:
-a:逻辑与,仅当两个条件都成立时,结果为真。
-o:逻辑或,两个条件只要有一个成立,结果为真。
[test]# vi test
1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh
echo “please input a file name:”
read file_name
if [ -d $file_name ]
then
echo $file_name is a directory
elif [ -f $file_name ]
then
echo “$file_name is a common file”
elif [ -c $file_name -o -b $file_name ]
then
12 echo “$file_name is a device file”
13 else
14 echo “$file_name is an unkown file”
15 fi
“test” 15L, 319C written
/etc/ is a directory
[test]# sh test
please input a file name:
/etc/inittab
/etc/inittab is a common file
[test]# sh test
please input a file name:
/dev/hdb
/dev/hdb is a device file
[test]# sh test
please input a file name:
/home/test
/home/test is an unkown file
for…done 语句
格式:for 变量 in 名字表
do
命令列表
done
[test]# vi test
1 #!/bin/sh
2 for DAY in Sunday Monday Tusday Webnesdday Thursday Friday Saturday
3 do
4 echo “The day is: $DAY”
5 done
“test” 5L, 114C written
[test]# sh test
The day is: Sunday
The day is: Monday
The day is: Tusday
The day is: Webnesdday
The day is: Thursday
The day is: Friday
The day is: Saturday
select 语句
select 变量 in 关键字
do
command 1
……
command n
done
select 把关键字中的每一项做成类似表单,以交互的方式执行 do 和 done 之间的命令。
[root@helen ~]# vi select
1 #!/bin/sh
2 # “select” Usage
3 echo “What is your favourite OS?”
4 select var in “Linux” “UNIX” “Windows” “Other” “Exit”
5 do
6 if [ $var = "Exit" ];then
7
break
8 else
9
echo “Your favourite OS is $var”
10 fi
11 done
12 echo “Goodbye!”
[root@helen ~]# sh select
What is your favourite OS?
1) Linux
2) UNIX
3) Windows
4) Other
5) Exit
#? 1
Your favourite OS is Linux
#? 2
Your favourite OS is UNIX
#? 3
Your favourite OS is Windows
#? 4
Your favourite OS is Other
#? 5
Goodbye!
case…esac 语句
格式:
case 变量 in
字符串 1) 命令列表 1
;;

字符串 n) 命令列表 n
;;
esac
[root@helen test]# vi case
1 #!/bin/sh
2 echo “”
3 echo “Please select your operation:”
4 echo “Press “C” to Copy”
5 echo “Press “D” to Delete”
6 echo “Press “B” to Backup”
7 echo “Please select your operation:”
8 read op
9 case $op in
10 C)
11
echo “your selection is Copy”
12 ;;
13 D)
14
echo “your selection is Delete”
15
;;
16 B)
17
echo “your selection is Backup”
18 ;;
19 *)
20
echo “invaline selection”
21 esac
[root@helen test]# sh case
Please select your operation:
Press C to Copy
Press D to Delete
Press B to Backup
Please select your operation:
D
your selection is Delete
while 语句
格式:
while 条件
do
命令
done
[root@helen test]# vi while
1 #!/bin/sh
2 num=1
3 while [ $num -le 10 ]
4 do
5 SUM=`expr $num \* $num`
6 echo “square of $num is:$SUM”
7 num=`expr $num + 1`
8 done
“while” 8L, 126C written
[root@helen test]# sh while
square of 1 is:1
square of 2 is:4
square of 3 is:9
square of 4 is:16
square of 5 is:25
square of 6 is:36
square of 7 is:49
square of 8 is:64
square of 9 is:81
square of 10 is:100
until 语句
格式:
until 条件
do
命令
done
until 类似 while 循环,不同的是 until 是条件返回值为假时才继续执行。
[root@helen test]# vi untill
1 #!/bin/sh
2 until [ -x /etc/inittab ]
3 do
4 /bin/ls -l /etc/inittab
5 exit 0
6 done
“untill” 6L, 81C written
[root@helen test]# sh untill
-rw-r–r– 1 root root 1666 02-22 23:16 /etc/inittab
跳出循环:break 和 continue
break:跳出整个循环
continue:跳过本次循环,进行下次循环
[root@helen test]# vi break
1 #!/bin/sh
2 while true

3 do
4 echo “******************************”
5 echo “Please select your operation:”
6 echo “1 Copy”
7 echo “2 Delete”
8 echo “3 Backup”
9 echo “4 Quit”
10 echo “******************************”
11 read op
12 case $op in
13
1)
14
echo “your selection is Copy”
15
;;
16
2)
17
echo “your selection is Delete”
18
;;
19
3)
20
echo “your selection is Backup”
21
;;
22
4)
23
echo “Exit …”
24
break
25
;;
26
*)
27
echo “invalide seletion,please try again”
28
continue
29 esac
30 done
“break” 30L, 527C written
shift 指令:参数左移,每执行一次,参数序列顺次左移一个位置,$#的值减 1,
用于分别处理每个参数,移出去的参数不再可用
[root@helen test]# vi shift
1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh
if [ $# -le 0 ]
then
echo “Not enough parameters”
exit 0
fi
sum=0
while [ $# -gt 0 ]
do
sum=`expr $sum + $1`
shift
12 done
13 echo $sum
[root@helen test]# sh shift 432 5432 2143 266
8273
函数应用
函数的定义:
函数名()
{
命令序列
}
函数的调用:不带()
函数名 参数 1 参数 2…
函数应用
函数中的变量:
变量均为全局变量,没有局部变量函数中的参数:调用函数时,可以传递参数,在函数中用
$1、$2…来引用
[root@helen test]# vi function
1 HELP()
2 {
3 echo “Usage: sh function \$1 \$2 \$3″
4 }
5
6 if [ $# -ne 3 ]
7 then
8 HELP
9 else
10 echo “thank for your input, the tree arguments is $1 $2 $3.”
11 fi
“function” 11L, 153C written
[root@helen test]# sh function 21 34 54
thank for your input, the tree arguments is 21 34 54.
awk 命令应用
awk-F 域分隔符‘命令’
awk -F 域分隔符,如果没有 F 是以空格为分隔符
[root@helen ~]# awk -F: ‘{print $1}’ /etc/passwd
检测系统中 UID 为 0 的用户

[root@helen ~]# awk -F: ‘$3==0 {print $1}’ /etc/passwd
root
[root@helen ~]# awk -F: ‘length($2)==0 {print $1}’ /etc/passwd 检测系统中密码为
空的用户
mary
hellen
[root@helen ~]# awk -F: ‘$7==”/sbin/nologin” {print $1}’ /etc/passwd 查找伪用户
Shell 脚本调试
sh -x script
这将执行该脚本并显示所有变量的值。
sh -n script
不执行脚本只是检查语法的模式,将返回所有语法错误。
[root@helen test]# cat shift
#!/bin/sh
if [ $# -le 0 ]
then
echo “Not enough parameters”
exit 0
fi
sum=0
while [ $# -gt 0 ]
do
sum=`expr $sum + $1`
shift
done
echo $sum
[root@helen test]# sh -x shift 23 45 21
+ ‘[' 3 -le 0 ']‘
+ sum=0
+ ‘[' 3 -gt 0 ']‘
++ expr 0 + 23
+ sum=23
+ shift
+ ‘[' 2 -gt 0 ']‘
++ expr 23 + 45
+ sum=68
+ shift
+ ‘[' 1 -gt 0 ']‘
++ expr 68 + 21
+ sum=89
+ shift
+ ‘[' 0 -gt 0 ']‘
+ echo 89
89
[root@helen test]# vi shift
1 #!/bin/sh
2 if [ $# -le 0 ]
3 then
4
echo “Not enough parameters”
5
exit 0
6 fi
7 sum=0
8 while [ $# -gt 0 ]
9 do
10
sum=`expr $sum + $1
少了一个`
11
shift
12 done
13 echo $sum
“shift” 13L, 157C written
[root@helen test]# sh -x shift 23 45 21
+ ‘[' 3 -le 0 ']‘
+ sum=0
shift: line 10: unexpected EOF while looking for matching “’
shift: line 14: syntax error: unexpected end of file
[root@helen test]# sh -n shift 23 45 21
shift: line 10: unexpected EOF while looking for matching “’
shift: line 14: syntax error: unexpected end of file
[root@helen test]#
Shell 脚本保护
1.创建用户 test,编辑 shell 脚本/home/test/script
2.修改用户 test 在/etc/passwd 中设置 test:x:101:100::/home/test:/home/test/script
3.修改脚本权限 chmod 700/export/home/test/script
4.其他用户执行此 shell 脚本,只需执行:
su-test
另:可以使用 shc 工具加密 shell 脚本
下载地址:http://www.datsi.fi.upm.es/~frosal/
su: /home/test/script: 可执行文件格式错误
Shell 应用实例
每分钟自动备份
[root@helen ~]# cat script
#!/bin/sh
DATE=`/bin/date +%H:%M`
/bin/tar -cf /backup/$1.$DATE.tar $1 > /dev/null 2>> /backup/$1.bak.log
/bin/gzip /backup/$1.$DATE.tar
if [ $? -eq 0 ]
then
echo “$1 $DATE backup successfully” >> /backup/$1.bak.log
else
echo “ERROR: failure $1 $DATE bakup!” >> /backup/$1.bak.log
[root@helen ~]# crontab -e
1 */1 * * * * /bin/sh /root/script inittab
检测非法 SetUID 程序:
[root@helen ~]# vi setuid.script
1 #!/bin/sh
2 #After the system intalled,please check setuid file first for security.
3 #mkdir /backup
4 #find / -perm -4000 -o -2000 > /backup/setuid.list
5 /usr/bin/find / -perm -4000 -o -perm -2000 > /tmp/setuid.check
6 for file in `/bin/cat /tmp/setuid.check`
7 do
8 /bin/grep $file /backup/setuid.list > /dev/null
9
if [ $? != "0" ]
10
then
11
echo “$file isn’t in list! it’s danger!!”
12
fi
13 done
14 /bin/rm /tmp/setuid.check
[root@helen ~]# sh setuid.script
/usr/bin/ssh-agent isn’t in list! it’s danger!!
/usr/bin/chage isn’t in list! it’s danger!!
/usr/bin/gpasswd isn’t in list! it’s danger!!
/usr/bin/write isn’t in list! it’s danger!!
/usr/bin/chsh isn’t in list! it’s danger!!