shell编程基础···初学者必用

来源:互联网 发布:淘宝闲鱼怎么用 编辑:程序博客网 时间:2024/04/29 18:24

1.shell基础知识 
作者:Stephen Bourne 在Bell实验室开发 
建议:man sh 查看相关UNIX上的改进或特性 

(1)shell提示符及其环境 
/etc/passwd文件 
提示符:$ 
/etc/profile $HOME/.profile 
(2)shell执行选项 
-n 测试shell script语法结构,只读取shell script但不执行 
-x 进入跟踪方式,显示所执行的每一条命令,用于调度 
-a Tag all variables for export 
-c "string" 从strings中读取命令 
-e 非交互方式 
-f 关闭shell文件名产生功能 
-h locate and remember functions as defind 
-i 交互方式 
-k 从环境变量中读取命令的参数 
-r 限制方式 
-s 从标准输入读取命令 
-t 执行命令后退出(shell exits) 
-u 在替换中如使用未定义变量为错误 
-v verbose,显示shell输入行 

这些选项可以联合使用,但有些显然相互冲突,如-e和-i. 

(3)受限制shell(Restircted Shell) 
sh -r 或 /bin/rsh 

不能执行如下操作:cd, 更改PATH,指定全路径名,输出重定向,因此可以提供一个较 
好的控制和安全机制。通常rsh用于应用型用户及拨号用户,这些用户通常是看不到提 
示符的。通常受限制用户的主目录是不可写的。 

不足:如果用户可以调用sh,则rsh的限制将不在起作用,事实上如果用户在vi及more 
程序中调用shell,而这时rsh的限制将不再起作用。 

(4)用set改变 shell选项 
用户可以在$提示符下用set命令来设置或取消shell的选项。使用-设置选项,+取消相应 
选项,大多数UNIX系统允许a,e,f,h,k,n,u,v和x的开关设置/取消。 

set -xv 
启动跟踪方式;显示所有的命令及替换,同样显示输入。 
set -tu 
关闭在替换时对未定义变量的检查。 

使用echo $-显示所有已设置的shell选项。 


(5)用户启动文件 .profile 
PATH=$PATH:/usr/loacl/bin; export PATH 

(6)shell环境变量 
CDPATH 用于cd命令的查找路径 
HOME /etc/passwd文件中列出的用户主目录 
IFS Internal Field Separator,默认为空格,tab及换行符 
MAIL /var/mail/$USERNAME mail等程序使用 
PATH 
PS1,PS2 默认提示符($)及换行提示符(>) 
TERM 终端类型,常用的有vt100,ansi,vt200,xterm等 

示例:$PS1="test:";export PS1 
test: PS1="$";export PS1 
$echo $MAIL 
/var/mail/username 
(7)保留字符及其含义 
$ shell变量名的开始,如$var 
| 管道,将标准输出转到下一个命令的标准输入 
# 注释开始 
& 在后台执行一个进程 
? 匹配一个字符 
* 匹配0到多个字符(与DOS不同,可在文件名中间使用,并且含.) 
$- 使用set及执行时传递给shell的标志位 
$! 最后一个子进程的进程号 
$# 传递给shell script的参数个数 
$* 传递给shell script的参数 
$@ 所有参数,个别的用双引号括起来 
$? 上一个命令的返回代码 
$0 当前shell的名字 
$n (n:1-) 位置参数 
$$ 进程标识号(Process Identifier Number, PID) 
>file 输出重定向 
>fiile 输出重定向,append 

转义符及单引号: 
$echo "$HOME $PATH" 
/home/hbwork /opt/kde/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin: 
$echo '$HOME $PATH' 
$HOME $PATH 
$echo $HOME $PATH 
$HOME /opt/kde/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/hbw 
ork/bin 

其他: 
$dir=ls 
$$dir 
$alias dir ls 
$dir 

ls > filelist 
ls >> filelist 
wc -l /dev/rmt/0h 

书写程序的目的是一次编程,多次使用(执行)! 

$ cat > backup.sh 
cd /home/hbwork 
ls * | cpio -o > /dev/rmt/0h 
^D 

执行: 
$ sh backup.sh 

或: 
$ chmod +x backup.sh 
$ ./backup.sh 

技巧:在shell script中加入必要的注释,以便以后阅读及维护。 

(2)shell是一个(编程)语言 
同传统的编程语言一样,shell提供了很多特性,这些特性可以使你的shell script 
编程更为有用,如:数据变量、参数传递、判断、流程控制、数据输入和输出,子 
程序及以中断处理等。 

. 在shell编程中使用数据变量可以将程序变量更为通用,如在上面backup.sh中: 
cd $WORKDIR 
ls * | cpio -o > /dev/rmt/0h 

. Shell编程中的注释以#开头 
. 对shell变量进行数字运算,使用expr命令 
expr integer operator integer 
其中operator为+ - * / %, 但对*的使用要用转义符,如: 
$expr 4 * 5 
20 
$int=`expr 5 + 7` 
$echo $int 
12 

(3)Shell编程的参数传递, 可通过命令行参数以及交互式输入变量(read) 

restoreall.sh 对backup.sh程序的备份磁带进行恢复 
$cat > restoreall.sh 
cd $WORKDIR 
cpio -i /dev/rmt/0h 
rm -rf * 

改进如下: 

#当使用了管道命令时,管理命令的返回代码为最后一个命令的返回代码 
if ls -a | cpio -o > /dev/rmt/0h 
then 
rm -rf * 
fi 

. if-then-else语句 
if command_1 
then 
command_2 
else 
command_3 
fi 

技巧: 由于shell对命令中的多余的空格不作任何处理,一个好的程序员会用这一特 
性 
对自己的程序采用统一的缩进格式,以增强自己程序的可读性. 

. 使用test命令进行进行条件测试 
格式: test conditions 

test在以下四种情况下使用: a. 字符比较 b.两个整数值的比较 
c. 文件操作,如文件是否存在及文件的状态等 
d. 逻辑操作,可以进行and/or,与其他条件联合使用 

a. 测试字符数据: shell变量通常民政部下均作为字符变量 
str1 = str2 二者相长,相同 
str1 != str2 不同 
-n string string不为空(长度不为零) 
-z string string为空 
string string不为空 

例: 
$ str1=abcd #在含有空格时必须用引号括起来 
$ test $str1=abcd 
$ echo $? 

$ str1="abcd " 
$ test $str1=abcd 
$ echo $? 

Note: 在test处理含有空格的变量时最好用引号将变量括起来,否则会出现错误的 
结果, 
因为shell在处理命令行时将会去掉多余的空格,而用引号括起来则可以防止 
shell去掉这些空格. 
例: 
$ str1=" " 
$ test $str1 
$ echo $? 

$ test "$str1" 
$ echo $? 

$ test -n $str1 
test: argument expected 
$ test -n "$str1" 
$ echo $? 



b. 整数测试: test与expr相同,可以将字符型变量转换为整数进行操作,expr进行 
整数的算术运算,而test则进行逻辑运算. 

表达式 说明 
--------------------------------------- 
int1 -eq int2 相等? 
int1 -ne int2 不等? 
int1 -gt int2 int1 > int2 ? 
int1 -ge int2 int1 >= int2 ? 
int1 -lt int2 int1 empty 
$ test -r empty 
$ echo $? 

$ test -s empty 

$ test ! -s empty 
$ echo $? 

e. 测试条件之逻辑运算 
-a And 
-o Or 

例: $ test -r empty -a -s empty 
$ echo $? 

f. 进行test测试的标准方法 
因为test命令在 shell编程中占有很重要的地位,为了使shell能同其他编程语言 
一样 
便于阅读和组织, Bourne Shell在使用test测试时使用了另一种方法:用方括号将 
整个 
test测试括起来: 

$ int1=4 
$ [ $int1 -gt 2 ] 
$ echo $? 


例: 重写unload程序,使用test测试 
#!/bin/sh 
#unload - program to backup and remove files 
#syntax: unload directory 

#check arguments 
if [ $# -ne 1 ] 
then 
echo "usage: $0 directory" 
exit 1 
fi 

#check for valid directory name 
if [ ! -d "$1" ] 
then 
echo "$1 is not a directory" 
exit 2 
fi 

cd $1 

ls -a | cpio -o > /dev/rmt/0h 

if [ $? -eq 0 ] 
then 
rm -rf * 
else 
echo "A problem has occured in creating backup" 
echo "The directory will not be ereased" 
echo "Please check the backup device" 
exit 3 
fi 
# end of unload 

在如上示例中出现了exit, exit有两个作用:一是停止程序中其他命令的执行,二 
是 
设置程序的退出状态 

g. if嵌套及elif结构 
if command 
then 
command 
else 
if command 
then 
command 
else 
if command 
then 
command 
fi 
fi 
fi 

改进:使用elif结构 
if command 
then 
command 
elif command 
then 
command 
elif command 
then 
command 
fi 

elif结构同if结构类似,但结构更清淅,其执行结果完全相同. 
-- 
Bourne Shell及Shell编程(2) 
h.交互式从键盘读入数据 
使用read语句,其格式如下: 

read var1 var2 ... varn 

read将不作变量替换,但会删除多余的空格,直到遇到第一个换行符(回车), 
并将输入值依次赋值给相应的变量。 

例: 
$ read var1 var2 var3 
Hello my friends 
$ echo $var1 $var2 $var3 
Hello my friends 
$ echo $var1 
Hello 
$ read var1 var2 var3 
Hello my dear friends 
$ echo $var3 
dear friends while循环: 
格式: 
while command 
do 
command 
command 
command 
... 
done 

例: 计算1到5的平方 
#!/bin/sh 

#Filename: square.sh 
int=1 

while [ $int -le 5 ] 
do 
sq=`expr $int * $int` 
echo $sq 
int=`expr $int + 1` 
done 
echo "Job completed" 

$ sh square.sh 



16 
25 
Job completed 

until循环结构: 
格式: 
until command 
do 
command 
command 
.... 
command 
done 

示例:使用until结构计算1-5的平方 
#!/bin/sh 

int=1 

until [ $int -gt 5 ] 
do 
sq=`expr $int * $int` 
echo $sq 
int=`expr $int + 1` 
done 
echo "Job completed" 

使用shift对不定长的参数进行处理 
在以上的示例中我们总是假设命令行参数唯一或其个数固定,或者使用$*将整个命 
令 
行参数传递给shell script进行处理。对于参数个数不固定并且希望对每个命令参 
数 
进行单独处理时则需要shift命令。使用shift可以将命令行位置参数依次移动位置 
, 
即$2->$1, $3->$2. 在移位之前的第一个位置参数$1在移位后将不在存在。 

示例如下: 

#!/bin/sh 

#Filename: shifter 

until [ $# -eq 0 ] 
do 
echo "Argument is $1 and `expr $# - 1` argument(s) remain" 
shift 
done 


$ shifter 1 2 3 4 
Argument is 1 and 3 argument(s) remain 
Argument is 2 and 2 argument(s) remain 
Argument is 3 and 1 argument(s) remain 
Argument is 4 and 0 argument(s) remain 


使用shift时,每进行一次移位,$#减1,使用这一特性可以用until循环对每个参 
数进行处理,如下示例中是一个求整数和的shell script: 

#!/bin/sh 
# sumints - a program to sum a series of integers 


if [ $# -eq 0 ] 
then 
echo "Usage: sumints integer list" 
exit 1 
fi 

sum=0 

until [ $# -eq 0 ] 
do 
sum=`expr $sum + $1` 
shift 
done 
echo $sum 


$ sh sumints 324 34 34 12 34 
438 


使用shift的另一个原因是Bourne Shell的位置参数变量为$1~$9, 因此通过位置变 
量 
只能访问前9个参数。但这并不等于在命令行上最多只能输入9个参数。此时如果想 
访问 
前9个参数之后的参数,就必须使用shift. 

另外shift后可加整数进行一次多个移位,如: 

shift 3 


. for循环 
格式: 
for var in arg1 arg2 ... argn 
do 
command 
.... 
command 
done 

示例: 
$ for letter in a b c d e; do echo $letter;done 






对当前目录下的所有文件操作: 
$ for i in * 
do 
if [ -f $i ] 
then 
echo "$i is a file" 
elif [ -d $i ] 
echo "$i is a directory" 
fi 
done 

求命令行上所有整数之和: 
#!/bin/sh 

sum=0 

for INT in $* 
do 
sum=`expr $sum + $INT` 
done 

echo $sum 


从循环中退出: break和continue命令 
break 立即退出循环 
continue 忽略本循环中的其他命令,继续下一下循环 

在shell编程中有时我们要用到进行无限循环的技巧,也就是说这种循环一直执行 
碰 
到break或continue命令。这种无限循环通常是使用true或false命令开始的。UNIX 
系统中的true总是返加0值,而false则返回非零值。如下所示: 

#一直执行到程序执行了break或用户强行中断时才结束循环 
while true 
do 
command 
.... 
command 
done 

上面所示的循环也可以使用until false, 如下: 

until false 
do 
command 
.... 
command 
done 

在如下shell script中同时使用了continue,break以及case语句中的正规表达式用 
法: 

#!/bin/sh 
# Interactive program to restore, backup, or unload 
# a directory 

echo "Welcome to the menu driven Archive program" 

while true 
do 
# Display a Menu 
echo 
echo "Make a Choice from the Menu below" 
echo _ 
echo "1 Restore Archive" 
echo "2 Backup directory" 
echo "3 Unload directory" 
echo "4 Quit" 
echo 

# Read the user's selection 
echo -n "Enter Choice: " 

read CHOICE 

case $CHOICE in 
[1-3] ) echo 
# Read and validate the name of the directory 

echo -n "What directory do you want? " 
read WORKDIR 

if [ ! -d "$WORKDIR" ] 
then 
echo "Sorry, $WORKDIR is not a directory" 
continue 
fi 

# Make the directory the current working directory 
cd $WORKDIR;; 

4) :;; # :为空语句,不执行任何动作 
*) echo "Sorry, $CHOICE is not a valid choice" 
continue 
esac 

case "$CHOICE" in 
1) echo "Restoring..." 
cpio -i /dev/rmt/0h;; 

3) echo "Unloading..." 
ls | cpio -o >/dev/rmt/0h;; 

4) echo "Quitting" 
break;; 
esac 

#Check for cpio errors 

if [ $? -ne 0 ] 
then 
echo "A problem has occurred during the process" 
if [ $CHOICE = 3 ] 
then 
echo "The directory will not be erased" 
fi 

echo "Please check the device and try again" 
continue 
else 
if [ $CHOICE = 3 ] 
then 
rm * 
fi 
fi 
done 


(6)结构化编程:定义函数 
同其他高级语言一样,shell也提供了函数功能。函数通常也称之为子过程(subroutine) 

其定义格式如下: 

funcname() 

command 
... 
command; #分号 


定义函数之后,可以在shell中对此函数进行调用,使用函数定义可以将一个复杂的程序 
分 
为多个可管理的程序段,如下所示: 

# start program 

setup () 
{ command list ; } 

do_data () 
{ command list ; } 

cleanup () 
{ command list ; } 

errors () 
{ command list ; } 

setup 
do_data 
cleanup 
# end program 

技巧: 
. 在对函数命名时最好能使用有含义的名字,即函数名能够比较准确的描述函数所 
完成 
的任务。 
. 为了程序的维护方便,请尽可能使用注释 


使用函数的另一个好处就是可以在一个程序中的不同地方执行相同的命令序列(函数), 
如下所示: 

iscontinue() 

while true 
do 
echo -n "Continue?(Y/N)" 
read ANSWER 

case $ANSWER in 
[Yy]) return 0;; <

原创粉丝点击