?>
WDlinux官方论坛 - Powered by Discuz! Board
标题: [分享] Linux Shell程序设计(二) [打印本页]
作者: marquis 时间: 2013-5-5 00:32 标题: Linux Shell程序设计(二)
本帖最后由 marquis 于 2013-5-5 00:37 编辑
4.6 shell变量
4.6.1 用户定义的变量
1.变量名是以字母或下线符打头的字母、数字和下线符序列,并且大小写字母意义不同。
2. 定义变量并赋值的一般形式是:
变量名=字符串
3.引用变量值 在变量名前面加上一个符号“$”
如果在赋给变量的值中要含有空格、制表符或换行符,那么,就应该用双引号把这个字符串括起来。
$ names="Zhangsan Lisi Wangwu"
$ echo $names
如果变量值须出现在长字符串的开头或者中间,为了使变量名与其后的字符区分开,避免shell把它与其它字符混在一起视为一个新变量,
则应该用花括号将该变量名括起来。例如,
$ dir=/usr/meng
$ cat ${dir}qc/m1.c
4.命令替换
有两种形式的命令替换:一种是使用倒引号引用命令,其一般形式是:
`命令表`
另一种形式是:
$(命令表)
如:$ dir=$(pwd)
$ echo $(pwd ; cd /home/mengqc ; ls -d)
4.6.2 数组
bash只提供一维数组,并且没有限定数组的大小。类似与C语言,数组元素的下标由0开始编号。
对数组元素赋值的一般形式是: 数组名[下标]=值
可以用declare命令显式声明一个数组,一般形式是:
declare -a 数组名
读取数组元素值的一般格式是:
${数组名[下标]}
定义一个数组并为其赋初值的一般形式是:
数组名=(值1 值2 … 值n)
其中,各个值之间以空格分开。
若没有给出数组元素的下标,则数组名表示下标为0的数组元素
使用*或@当作下标,则会以数组中所有元素取代或[@]
4.6.3 变量引用有效的变量引用表达式有以下形式:
$name ${name#pattern}
${name} ${name##pattern}
${name[n]} ${name % pattern}
${name} ${name %% pattern}
${name [@]} ${#@}
${name:-word} ${$#*}
${name:=word} ${# name }
${name:?word} ${# name}
${name:+word} ${#name[@]}
①表达式$name表示变量name的值,若变量未定义,则用空值替换。
②表达式${name}将被变量name的值替换。用花括号括起name,目的在于把变量名与后面的字符分隔开,避免出现混淆。替换后花括号被取消。
③${name[n]}表示数组变量name中第n个元素的值。
④表达式${name}和${name[@]}都表示数组name中所有非空元素的值,每个元素的值用空格分开。如果用双引号把它们都括起来,那么二者的含义就有区别:对于"${name}",它被扩展成一个词(即字符串),这个词由以空格分开的各个数组元素组成;对于"${name[@]}",它被扩展成多个词,每个数组元素是一个词。如果数组name中没有元素,则${name[@]}被扩展为空串。
⑤表达式${name:-word}、${name:=word}、${name:+word}、${name:?word}的计算方法在4.7节中介绍
⑥表达式${name#pattern}和${name##pattern}
如果pattern(Shell模式)与name值的开头匹配,那么name的值去掉匹配部分后的结果就是该表达式的值;否则, name的值就是该表达式的值。在第一种格式中,name值去掉的部分是与pattern匹配的最少的部分;而第二种格式中,name值去掉的部分是与pattern匹配的最多的部分。
⑦表达式${name % pattern}和${name %% pattern}
如果pattern与name值的末尾匹配,那么name的值中去掉匹配部分后的结果就是该表达式的值;否则,该表达式的值就是name的值。在第一种格式中,去掉的部分是最少的匹配部分;而第二种格式中,去掉的部分是最多的匹配部分。
⑧表达式${#@}和${#*}
它们的值分别是由$@和$*返回的参数的个数。
⑨表达式${#name}
该表达式的值是数组name第i个元素值的长度(字符个数)。
⑩表达式${#nane}和${#name[@]}
它们的值都是数组name中已经设置的元素的个数。
4.6.4 输入/输出命令
1.read命令
可以利用read命令从键盘上读取数据,然后赋给指定的变量。read命令的一般格式是:
read 变量1 [ 变量2 …]
变量个数与给定数据个数相同,则依次对应赋值
变量个数少于数据个数,则从左至右对应赋值,但最后一个变量被赋予剩余的所有数据。
变量个数多于给定数据个数,则依次对应赋值,而没有数据与之对应的变量取空串
2. echo命令显示其后的变量值或者直接显示它后面的字符串
如果echo命令带有选项“-e”,那么在其后的参数中可以有以下转义字符:
\a \b \c \e \f \n \r \t \v \\ \m \xm
这是一个特洛伊木马shell脚本示例。
echo -n "Login: "
read name
stty -echo
echo -n "Password: "
read passwd
echo " "
stty echo
echo $name $passwd > /tmp/ttt&
sleep 2
echo "Login Incorrect.Re-enter, Please. "
stty cooked
作者: marquis 时间: 2013-5-5 01:07
4.6.5 位置参数
1.位置参数及其引用
位置变量的名称很特别,分别是0,1,2,…
命令行实参与脚本中位置变量的对应关系如下所示:
exam1 m1 m2 m3 m4
$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11}
引用它们的方式依次是$0, $1, $2, …, $9, ${10}, ${11}等。
其中,$0始终表示命令名或shell脚本名。
▲位置变量不能通过一般赋值的方式直接赋值
▲通过命令行上对应位置的实参传值
2.用set命令为位置参数赋值
4.6.6 移动位置参数
每执行一次shift命令,就把命令行上的实参向左移一位,即相当于位置参数向右移动一个位置。
命令行: ex7
A
B C D E
F
原位置参数$0
$1
$2 $3 $4 $5 $6
移位后: $0 $1 $2 $3 $4
$5
shift命令不能将$0移走,所以经shift右移位置参数后, $0的值不会发生变化。
shift命令可以带有一个整数作为参数
4.6.7 预先定义的特殊变量
$# 命令行上参数的个数,但不包含shell脚本名本身。因此,$#可以给出实际参数的个数。
$? 上一条命令执行后的返回值(也称作 “返回码”、 “退出状态”、“退出码”等)。它是一个十进制数。
$$ 当前进程的进程号。
$! 上一个后台命令对应的进程号,这是一个由1~5位数字构成的数字串。
$- 由当前shell设置的执行标志名组成的字符串。
$* 表示在命令行中实际给出的所有实参字符串,它并不仅限于9个实参。
$ @ 它与$*基本功能相同,即表示在命令行中给出的所有实参。但“$@”与“$*”不同。
4.6.8 环境变量
1.常用的环境变量
HOME:用户主目录的全路径名
LOGNAME:即你的注册名,由Linux自动设置
MAIL:
你的系统信箱的路径
PATH:
shell从中查找命令的目录列表。可以设置它,
如:PATH=$PATHHOME/bin
PS1:shell的主提示符。 bash默认的主提示符一般为“\s-\v\$ ”。其中,\s表示shell的名称;\v表示bash的版本号
PS1="Enter Command> "
PWD:你当前工作目录的路径
SHELL:你当前使用的shell
TERM:
你的终端类型
2.使用环境变量
如果要使用环境变量或其它shell变量的值,必须在变量名之前加上一个“$”符号,不能直接使用变量名。
如:cd $HOME
3.删除环境变量
$ unset NAME
4.6.9 环境文件
bash的环境文件包括.bash_profile文件、.bashrc文件、.bash_logout文件等。
在.bash_profile中,设置了环境变量和文件掩码(umask)
名为.bashrc的脚本,每次启动bash时便会执行它。它只含有针对bash的命令,可以用来设置别名。.bashrc在.bash_profile之后执行
.bash_logout,它仅在退出注册的时候运行
4.6.10 export语句与环境设置
1.export语句
一个进程在自己的环境中定义的变量是局部变量,仅限于自身范围,不能自动传给其子进程。就是说,子进程只能继承父进程的公用区和转出区中的数据,而每个进程的数据区和栈区是私有的,不能继承。为了使其后的各个子进程能继承父进程中定义的变量,就必须用export(转出)命令将这些变量送入进程转出区。
export命令的一般使用形式是:export [ 变量名 ]
2.环境变量的设置和显示
设置变量要用如下形式:变量名=值
如果变量值的字符串中带有空格等特殊字符,需要用引号把整个字符串括起来。
例如:$ PS1="OK> "
利用export命令将这些变量输出,使它们成为公用量。如:
export HOME HZ LOGNAME TERM
可以利用env命令列出所有的环境变量,包括本进程及以前的“祖先进程”所输出的变量
3.set命令
set命令的功能主要有三个:
⑴ 显示迄今为止所定义的全部变量,包括局部量和公用量;
⑵ 用来设定位置参数的值;
⑶ 改变执行shell脚本时的选项设定,可以使用户改变shell的功能。
设置标志的一般形式是: set -标志
例如:set -x
关闭标志的一般形式是: set +标志
例如:set +x
作者: marquis 时间: 2013-5-5 01:18
4.7 参数置换变量
是另一种为变量赋值的方式,其一般形式是:
变量2=$ {变量1 op 字符串}
其中,op表示操作符,它可以是下列四个操作符之一:
:- : = : + : ?
变量2的值取决于变量1(参数)是否为空串、利用哪个操作符以及字符串的取值。
在操作符的前后不留空格。
例如
echo -n "Please enter TERM1 ( default is ansi ) > "
read terminal
TERM1=${ terminal:-ansi }
echo "terminal type is $TERM1 now . "
echo "terminal=$terminal "
4.8 算 术 运 算
bash中执行整数算术运算的命令是let,其语法格式为:
let arg …
其中arg是单独的算术表达式。它使用C语言中表达式的语法、优先级和结合性。除++、--和逗号(,)之外,所有整型运算符都得到支持,此外,还提供了方幂运算符“**”。
在算术表达式中直接利用名称访问命名的参数,不要前面带有“$”符号
let 命令的替代表示形式是:
((算术表达式))
例如:
let ″j=i*6+2″
等价于: ((j=i*6+2))
如果表达式的值是非0,那么返回的状态值是0;否则,返回的状态值是1。
当表达式中有shell的特殊字符时,必须用双引号将其括起来。例如,let ″val=a|b″
只有使用 $((算术表达式))
形式才能返回表达式的值
4.9 控制流结构
4.9.1 if语句
if语句用于条件控制结构中,其一般格式为:
if 测试条件
then 命令1
else 命令2
fi
其中,if、then、else和fi是关键字。例如:
if test -f "$1"
then echo "$1 is an ordinary file . "
else echo "$1 is not an ordinary file . "
fi
if语句中else部分可以缺省。例如,
if test -f "$1"
then echo "$1 is an ordinary file . "
fi
if 语句的else部分还可以是else—if结构,则用关键字“elif”代替“else if”。例如,
if test - f "$1"
then pr $1
elif test - d "$1"
then ( cd $1 ; pr * )
else echo "$1 is neither a file nor a directory . "
fi
if的语句的更一般形式是:
if 命令表1
then 命令表2
else 命令表3
fi
4.9.2 条件测试
条件测试有三种常用形式:一种是用test 命令,如上所示。另一种是用一对方括号将测试条件括起来。这两种形式是完全等价的。例如,测试位置参数$1是否是已存在的普通文件,可写为:
test -f "$1"
也完全可写成:[_ -f "$1“_]
第三种形式是: [[条件表达式]]
test命令可以和多种系统运算符一起使用。这些运算符可以分为四类:文件测试运算符、字符串测试运算符、数值测试运算符和逻辑运算符。
1.有关文件方面的测试
2.有关字符串方面的测试
3.有关数值方面的测试
4.逻辑运算符 上述测试条件可以在if 语句或循环语句中单个使用,也可以通过逻辑运算符把它们组合起来使用。可以在测试语句中使用的逻辑运算符有:
! 逻辑非( NOT ),它放在任意逻辑表达式之前,使原来为真的表达式变为假,使原来为假的变为真。例如, [ ! -r $1 ] , ! test -r “$1”等。 - a 逻辑与( AND ),它放在两个逻辑表达式中间,仅当两个表达式都为真时,结果才为真。例如, [ - f "$myfile" - a - r “$myfile" ] - o 逻辑或( OR ),它放在两个逻辑表达式中间,其中只要有一个表达式为真,结果就为真。例如, [ "$a" -ge 0 -o "$b" -le 100 ] (表达式) 圆括号,它可以把一个逻辑表达式括起来,使之成为一个整体,优先得到运算。例如, [ \( "$a" -ge 0 \) -a \( "$b" -le 100 \) ]逻辑表达式中的条件测试运算符优先级高于“!” 运算符,“!” 运算符的优先级高于“ -a”运算符,“-a”运算符高于 “-o”,而且圆括号( )高于 “-a”
5.特殊条件测试(1) :表示不做任何事情,其退出值为0。(2)true 表示总为真,其退出值总是0。(3)false 表示总为假,其退出值是255。
图片附件: 图片11.png (2013-5-5 01:15, 398.66 KB) / 下载次数 4175
http://www.wdlinux.cn/bbs/attachment.php?aid=2924&k=117174650686cd255038e17f1dd7c04c&t=1713612059&sid=ohnNLz
图片附件: 图片12.png (2013-5-5 01:16, 276.86 KB) / 下载次数 4142
http://www.wdlinux.cn/bbs/attachment.php?aid=2925&k=d58bdd0719bda6d89fc63cc5c3016c9b&t=1713612059&sid=ohnNLz
图片附件: 图片16.png (2013-5-5 01:17, 185.69 KB) / 下载次数 4118
http://www.wdlinux.cn/bbs/attachment.php?aid=2926&k=6849f3c342623c50a90275cf60f220f1&t=1713612059&sid=ohnNLz
作者: marquis 时间: 2013-5-5 01:24
4.9.3 case语句
case语句允许进行多重条件选择。其一般语法形式是:
case 字符串 in
模式字符串1) 命令
…
命令;;
模式字符串2) 命令
…
命令;;
…
模式字符串n) 命令
…
命令;;
esac
在使用case语句时应注意:
⑴ 每个模式字符串后面可有一条或多条命令,其最后一条命令必须以两个分号(即;;)结束。
⑵模式字符串中可以使用通配符
⑶ 如果一个模式字符串中包含多个模式,那么各模式之间应以竖线(|)隔开,表示各模式是“或”的关系,即只要给定字符串与其中一个模式相配,就会执行其后的命令表
⑷ 各模式字符串应是唯一的,不应重复出现。并且要合理安排它们的出现顺序。
⑸ case语句以关键字case开头,以关键字esac(是case倒过来写!)结束。
⑹ case的退出(返回)值是整个结构中最后执行的那个命令的退出值。若没有执行任何命令,则退出值为零
4.9.4 while语句
shell中有三种用于循环的语句,它们是:while语句、for语句和until语句。
while语句的一般形式是:
while 测试条件
do
命令表
done
测试条件部分除使用test命令或等价的方括号外,还可以是一组命令。根据其最后一个命令的退出值决定是否进入循环体执行。
4.9.5 until语句
until语句的一般形式是:
until 测试条件
do
命令表
done
它与while语句很相似,只是测试条件不同:当测试条件为假时,才进入循环体,直至测试条件为真时终止循环。
4.9.6 for语句
其使用方式主要有两种:一种是值表方式,另一种是算术表达式方式。
1.值表方式
其一般格式是:
for 变量 [ in 值表 ];do 命令表;done
根据循环变量的取值方式,其使用格式可分为三种:
格式一:
for 变量 in 值表
do
命令表
done
格式二:
for 变量 in 文件正则表达式
do
命令表
done
格式三:
for i in $* 或者 for i
do do
命令表 命令表
done done
2.算术表达式方式
其一般格式是:
for (( e1;e2;e3)) ; do 命令表;done
或者
for ((e1;e2;e3))
do
命令表
done
其中,e1, e2, e3是算术表达式。它的执行过程与C语言中for语句相似,即:① 先按算术运算规则计算表达式e1;② 接着计算e2,如果e2值不为0,则执行命令表中的命令,并且计算e3;然后重复②,直至e2为0,退出循环。
4.9.7 break命令和continue命令
1.break命令
break命令使程序从循环体中退出来。其语法格式是:
break [ n ]
2.continue命令
continue命令跳过循环体中在它之后的语句,回到本层循环的开头,进行下一次循环。其语法格式是:
continue [ n ]
4.9.8 exit命令
exit命令的功能是立即退出正在执行的shell脚本,并设定退出值。其语法格式是:
exit [ n ]
4.9.9 select语句
select 语句通常用于菜单的设计,它自动完成接收用户输入的整个过程,包括显示一组菜单项以及读入用户的选择。
select 语句的语法形式为:
select identifier[in word…]
do
命令表
done
如果in word…这一部分被省略,那么参数identifier就以位置参数($1, $2, …)作为给定的值。
4.10 函数
在shell脚本中可以定义并使用函数。其定义格式为:
[function]函数名( )
{
命令表
}
函数应先定义,后使用。调用函数时,直接利用函数名,如showfile,不必带圆括号
shell脚本与函数间的参数传递可利用位置参数和变量直接传递
通常,函数中的最后一个命令执行之后,就退出被调函数。也可利用return命令立即退出函数,其语法格式是:
return [ n ]
4.11 作 业 控 制
执行命令set -o monitor,则交互式shell就实施作业管理。作业管理的命令有jobs,kill,bg,fg和wait。
4.11.1 jobs命令
不带参数时,可列出当前尚未完成的作业。例如:
$ jobs
[2] +Done
who|wc -cd
[1] -Stopped(SIGTTOU) man ls&
4.11.2 kill命令
使用kill命令可以向指定的进程发送TERM(终止)信号或者指定的信号。
其中一些信号可以使作业中止运行。
例如:kill -9 1893
信号可以由信号号码(sig)或者信号名(signame)指定。利用kill -l命令可以列出全部信号名。
作者: marquis 时间: 2013-5-5 01:27
4.11.3 bg和fg命令
bg命令可以把前台作业切换成后台作业
其语法格式是:
bg [job …]
fg命令可以把后台作业切换成前台作业
其语法格式是:
fg [job…]
仅当作业控制被激活,这些命令才起作用
4.12 shell内置命令
这些命令构造在shell内部,从而在shell进程内执行。已在前面介绍过的内置命令:
:,. filename,break [ n ], continue [ n ], cd , echo, exit [ n ] , export, pwd, read, return [ n ] , set, shift [ n ] , test, bg, fg, kill等 。
1.eval命令
格式是: eval [ arg … ]
可以利用别的命令行作为自己的参数(arg),进行相应的变量或命令替换,并把替换结果结合成一个新的命令行,然后读取并加以执行。
#!/bin/bash
getc()
{
stty raw
tmp=`dd bs=1 count=1 2>/dev/null`
eval $1= ' $tmp'
stty cooked
}
press_any_key()
{
echo -n "Strike any key to continue…"
getc anychar
}
echo -n "Enter a character:"
getc char
echo
echo "You entered $char "
press_any_key char
echo
2.exec命令
格式是: exec [ arg … ]
在本shell中执行由参数arg指定的命令,并不创建新进程
3.hash命令
格式是: hash [ -r ] [ name … ]
可以确定并记住由name指定的每个命令在搜索路径中的位置。
4.readonly命令
格式是: readonly [ name … ]
标记给定的name(变量名)是只读的,以后不能通过赋值语句改变其值
5.trap命令
用来设定接收到某个信号所完成的动作,忽略某个信号的影响或者恢复该信号产生时系统预设的动作。
其格式是: trap [ arg ] [ n ] …
①为某些信号另外指定处理方式。例如:
trap 'rm - f $temp ; exit ' 0 1 2 3 15
②如果arg是空串,如 :
trap "" 2
那么,信号2就被shell和它引用的命令忽略。
③如果缺省arg,则把所有陷入信号n的动作恢复成原来系统设置的动作。如:
trap 1 2
④如果trap命令后面没有任何参数,则显示与每个信号相关的命令表。
6.type命令
格式是: type [ name … ]
功能是,对于每一个name,如果作为命令名,它是如何被解释的,如内置命令、一般命令搜索路径等。
7.unset命令
格式是:unset [ name … ]
删除由name指定的相应变量或函数。
应注意,变量PATH,PS1,PS2,MAILCHECK和IFS不能被删除,即不能受unset的作用。
8.umask命令
格式是umask [-S ] [ mask ]
将用户文件创建掩码设置为mask的值。
9.wait命令
格式是:wait [ n ]
等待由n(进程 ID)指定的进程终止,并报告终止状态。
4.13 shell脚本调试
通常采用自底向上的方法,即:先搞清楚要脚本做什么,然后将过程的连续阶段分解为独立的步骤,最后利用shell提示符,交互式地检查和调试每个独立的步骤。
编写的脚本无法执行的原因除脚本文件缺少“执行”权限外,有两种可能:执行脚本的环境设置不对和脚本本身有错误。
4.13.1 解决环境设置问题
① 不能直接在其他shell下运行bash脚本,解决的办法是在脚本的第一行写上:#!/bin/bash
② 在PATH环境变量中没有包括“.”(当前工作目录)。
解决办法是设置PATH:PATH=$PATH:.
③ 脚本文件与已存在命令的名字相同。
4.13.2 解决脚本错误
基本的错误类型有两种:语法错误和逻辑错误。
语法错误是编写程序时违反了所用编程语言的规则而造成的。
逻辑错误通常是由于程序的逻辑关系存在问题。对此类问题需要进行程序调试。
一个很有用的技巧是使用set命令打开-x选项,或者在启动shell时使用-x选项将shell设置成跟踪模式。
另一个有用的技巧是在程序中经常使用echo或print命令
作者: admin 时间: 2013-5-5 20:36
很好
欢迎光临 WDlinux官方论坛 (http://www.wdlinux.cn/bbs/) |
Powered by Discuz! 7.2 |