1.59k likes | 2.05k Views
Shell 编程. 1 Shell 的基本概念 2 Shell 语法 3 正则表达式 4 Shell 编程综合实例. 1 Shell 的基本概念. 1.1 Shell 的概念 Shell 是一个命令语言解释器,它拥有自己内建的 Shell 命令集, Shell 也能被系统中其他应用程序调用。用户在提示符下输入的命令都由 Shell 解释后传给 Linux 核心。 Shell 、用户及 Linux 操作系统内核之间关系如图 1 所示。. 图 1 Shell 、用户及 Linux 操作系统内核之间关系.
E N D
Shell编程 1 Shell的基本概念 2 Shell语法 3 正则表达式 4 Shell编程综合实例
1 Shell的基本概念 1.1 Shell的概念 Shell是一个命令语言解释器,它拥有自己内建的Shell命令集,Shell也能被系统中其他应用程序调用。用户在提示符下输入的命令都由Shell解释后传给Linux核心。 Shell、用户及Linux操作系统内核之间关系如图 1所示。
Shell的另一个重要特性是它自身就是一个解释型的程序设计语言。 Shell程序设计语言支持绝大多数在高级语言中能见到的程序元素,如函数、变量、数组和程序控制结构。 Shell编程语言简单易学,任何在提示符中能键入的命令都能放到一个执行的Shell程序中。
【技巧】 如何查看用户登录系统时默认使用的Shell? ① 最简单的方式是执行echo命令,查询系统环境变量的值: [root@redflag /root]# echo $SHELL /bin/bash ② 执行finger命令查看用户数据,也能看到用户默认的Shell: [root@redflag /root]#finger –l root Login: root Name: root Directory: /root Shell: /bin/bash
③ 查看/etc/passwd文件,注意用“:”分隔的最后一列,就是该用户的默认的Shell,该文件的内容如下: root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin: daemon:x:2:2:daemon:/sbin: adm:x:3:4:adm:/var/adm: lp:x:4:7:lp:/var/spool/lpd: rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/bin/false test:x:500:500::/home/test:/bin/bash
1.3 创建及执行Shell脚本 1. 创建Shell脚本文件 Shell脚本是指使用用户环境Shell提供的语法所编写的脚本。 如果你经常用到相同执行顺序的操作命令,便可以将这些命令写成脚本文件,这样以后要做同样的事情时,只要在命令行输入其文件名即可。
【实例 3】 该实例会显示当前的日期时间、执行路径、用户账号及所在的目录位置。 在文本编辑器中输入下列内容,并存为showinfo: #!/bin/bash #This script is a test! echo –n "Date and time is: " date
echo –n "The Executable path is : "$PATH echo "Your name is : `whoami` " echo –n "Your Current directory is : " pwd #end
2. 执行Shell脚本 编辑脚本之后,如何来运行呢?一般有四种方法,下面来分别介绍。 (1) 将脚本的权限设置为可执行,这样就可以在Shell的提示符下直接执行。可以使用 chmod命令更改Shell脚本的权限: chmod u+x showinfo chmod u+x,g+x showinfo chmod a+x showinfo
如何指定使用哪一个Shell来解释执行脚本呢? ① 如果Shell脚本的第一个非空白字符不是“#”,则它会使用Bourne Shell。 ② 如果Shell脚本的第一个非空白字符是“#”,但不是以“#!”开头时,则它会使用C Shell。 ③ 如果Shell脚本以“#!”开头,则“#!”后面所跟的字符串就是所使用Shell的绝对路径名。Bourne Shell的路径名称为/bin/sh,而C Shell则为/bin/csh。
(2) 执行Shell脚本想要执行的Shell,其后跟随Shell脚本的文件名作为命令行参数。 例如,使用tcsh执行上面的Shell脚本: tcsh showinfo 此命令启动一个新的Shell,并令其执行showinfo文件。
(3) 在pdksh和Bash下使用“.”命令,或在tcsh下使用source命令。例如,在pdksh和Bash下执行上面的Shell脚本: . showinfo 或在tcsh下执行上面的Shell脚本: source showinfo
2 Shell 语法 2.1 Shell变量 变量,就是可存放数据的识别符。在pdksh和Bash中,给变量赋值的方法是一样的,即在变量名后紧跟着等号和变量值。 例如,要把变量10赋给变量a,则使用下面的命令: a=10
在tcsh中,可以使用如下的命令: set a=10 给字符串赋值的方法与给整数赋值的方法相同。例如: str=name 为了读取变量的值,需要使用“$”符号。例如,用如下的命令将a变量的值输出到屏幕上: echo $a 除了自定义的变量外,还有一些系统默认的特殊变量,这些变量也是常常应用在脚本程序中的,这些常用的变量如表 1所示。
MAILCHECK 变 量 功 能 HOME 用户的主目录 PATH 执行命令时所搜索的目录 TZ 时区 终端的类型 检查新邮件的时间间隔 PS1 在Shell命令行的提示符 PS2 在命令尚未输入完时,Shell要求再输入的提示符 MANPATH man指令的搜索路径 TERM 表 1 常 用 的 变 量
要想查看变量的值,用echo命令即可。 表 1介绍的变量是系统默认的变量,还有一些变量是在执行Shell程序时系统给设置好的,并且不能加以修改,这些变量也是相当有用的,如表 2所示。
存储Shell程序的程序名 变 量 功 能 # 存储Shell程序中命令行参数的个数 ? 存储上一个执行命令的返回值 0 存储上一个后台执行命令的PID * 存储Shell程序的所有参数 @ 存储所有命令行输入的参数 $ 存储Shell程序的PID ! 表2 系统设置好的变量
【实例 4】 下面的程序会显示所有参数及其总数,将其存为showarg文件,源代码如下: #!/bin/bash echo "All argument list : $@ " //存储所有命令行输入的参数 echo "The total number of argument is : $#" //存储Shell程序中命令行参数的个数 #end
存盘后执行chmod a+x showarg [root@redflag /root]# ./showarg red flag linux //输入三个参数 All argument list : red flag linux //显示参数 The total number of argument is : 3 //显示参数的个数
2.2类型声明 declare • 为什么会这样呢,是因为linux不知道变量的类型。 • 解决方法就是使用 declare
数值运算 • (( )) • 适用范围:只适用于bash和ksh,不支持csh。 • 实例: • ((sum=10+2*((((3+1))*((5-1))/2)))); • echo $sum;
2.3 条件命令 1. 条件测试 在Bash和pdksh环境中,测试条件表达式只能通过使用test命令来完成。test命令的用法如下: test expression 注意:各项中间加空格!
【实例 6】 [root@redflag /root]# test 8 = 8 //测试字符串8等于8 [root@redflag /root]# echo $? //显示其返回值,变量$存储上一个执行命令返回值 0 //其值为真,返回0 [root@redflag /root]# test 8 = 9 //测试字符串8等于9 [root@redflag /root]# echo $?
1 //其值为真,返回0 [root@redflag /root]# [ 8 = 8 ] //省略“test”,改用中括号,作用完全一样 [root@redflag /root]# echo $? 0 [root@redflag /root]# [ 8 = 9 ] //省略“test”,改用中括号,作用完全一样 [root@redflag /root]# echo $? 1
test命令可以和多种系统运算符一起使用。 运算符可以分为四类: 整数运算符 字符串运算符 文件运算符 逻辑运算符。 在不同的Shell环境中,条件表达式的语法有些不同,本书主要介绍Bash、pdksh和tcsh,其中Bash和pdksh的语法相同。下面分别介绍。
在Bash和pdksh环境中: (1) 数值运算符:用来判断数值表达式的真假。可用的运算符如下: int1 -eq int2 如果int1 = int2,则为真。 int1 -ge int2 如果int1 >= int2,则为真。 int1 -gt int2 如果int1 > int2,则为真。 int1 -le int2 如果int1 <= int2,则为真。 int1 -lt int2 如果int1 < int2,则为真。 int1 -ne int2 如果int1 != int2,则为真。
【实例 7】 [root@redflag /root]# [ text -gt abc ] //测试整数text是否大于abc [:text:integer expression expected //数据类型错误 [root@redflag /root]# [ 100 -gt 200 ] //100大于200吗? [root@redflag /root]# echo $? //显示其返回值 1 //其值为假,返回1
(2) 字符串运算符:用来判断字符串表达式的真假。可用的运算符如下: str1 = str2 如果str1和str2相同,则为真。 str1 != str2 如果str1和str2不相同,则为真。 str 如果str不为空,则为真。 -n str 如果str的长度大于零,则为真。 -z str 如果str的长度等于零,则为真。
【实例 8】 [root@redflag /root]# [ text = TEXT ] //测试字符串text是否等于TEXT [root@redflag /root]# echo $? //显示其返回值 1 //其值为假,返回1(区分大小写) [root@redflag /root]# [ $PWD ] //测试环境变量PWD是否有值 [root@redflag /root]# echo $? 0 //其值为真,返回0
(3) 文件运算符:用来判断文件是否存在、文件类型及属性。可用的运算符如下: -d filename 如果filename为目录,则为真。 -f filename 如果filename为普通的文件,则为真。 -r filename 如果filename为只读,则为真。 -s filename 如果filename的长度大于零,则为真。 -w filename 如果filename为可写,则为真。 -x filename 如果filename为可执行,则为真。
【实例 9】 [root@redflag /root]# [ -d /etc ] //判断/etc是否为目录 [root@redflag /root]# echo $? //显示其返回值 0 //其值为真,返回0 [root@redflag /root]# [ -w /etc ] //判断root对目录/etc是否有写的权限 [root@redflag /root]# echo $? //显示其返回值 0 //其值为真,返回0,有写的权限
(4) 逻辑运算符:用来结合表达式或取得表达式相反值。可用的运算符如下: !expr (非) 如果expr为假,则返回真。 expr1 -a expr2(与)如果expr1和expr2同时为真,则返回真。 expr1 -o expr2 (或)如果expr1或expr2有一个为真,则返回真。
【实例 10】 [root@redflag /root]# [ -f file1 –a –w file1 ] //file1存在且具有可写的权限 [root@redflag /root]# echo $? //显示其返回值 0 //其值为真,返回0
2.2 条件语句 1) if语句 if语句可根据表达式的值是真或假来决定要执行的程序段落,其语法如下: if expressionl //若expressionl为真 then commands //则执行这些命令 elif expression2 //否则若expression2为真
then commands //则执行这些命令 else //若以上的表达式都不成立 commands //则执行这些命令 fi //结束if语句
注意: • fi是if语句的结束符(刚好是if倒过来),必须与if成对出现,而elif及else子句可有可无。 • elif是else if的简写,当if的表达式不成立时,才会接着测试elif的表达式。如果if及elif的测试条件都不成立,最后才会执行else子句内的命令。 • 一个if可以有好几个elif子句,但只能有一个else子句。
【实例 11】 此实例将显示目录内是否有example_if文件,源代码如下: #!/bin/bash #This is example1 about if. if [ -f example_if ] //判断文件是否存在 then echo "There is a example_if file in current directory. " else echo "no example_if file in current directory. " fi #end
【实例 12】 此实例在键盘上读取一个字符,然后根据字符的值来判断。 #!/bin/bash #This is example2 about if. echo –n "Please input the answer: " //-n不换行 read I //从键盘读入 if [ $I = y ] then
echo "The answer is right" elif [ $I = n ] then echo "The answer is wrong" else echo "Bad Input." fi #end
【技巧】 如何从键盘一次读入多个变量? 用语句read var1 var2 …… 变量之间用空格隔开。例如: read name gender //读入两个变量 echo $name echo $gender 假如在键盘输入linux man,则上边的语句执行的结果为: linux //变量name的值 man //变量gender的值 如果输入文本过长,Shell将所有的超长的部分赋给最后一个变量。
2) case语句 case语句用来从很多的测试条件中选择符合的条件执行。其语法如下: case string in //测试string字符串 str1) //若str1符合 commands;; //则执行这些命令 str2) commands;; *) //若str1和str2都不符合 commands;; //则执行这些命令 esac //结束case语句
注意: • case语句适用于字符串的比较,其测试条件可用通配符。 • 双分号(;;)为测试条件的结束,在每一个测试条件成立后,一直到双分号之前的命令,都会被Shell执行。 • 使用通配符作为测试条件时,不要在字符串左右加上双引号,因为这样会使字符串无法正确匹配。 • 由于所有字符串都可以与通配符“*”匹配,因此“*”之后的命令可以视为case语句默认的执行命令。
【实例 13】 此实例检查命令行的第一个参数是否为“-i”或“-e”,如果是“-i”,则计算由第二个参数指定的文件中以i开头的字数;如果是“-e”,则计算由第二个参数指定的文件中以e开头的字数。如果第一个参数既不是“-i”也不是“-e”,则在屏幕上显示一条错误的信息。该实例源代码如下:
#!/bin/bash #This is example1 about case. case $1 in //$1是命令行第一个参数 -i ) count=`grep ^i $2|wc –l` //查找并计算以i开头的行数,“ ` ”是反引号 echo "The number of lines in $2 that start with an i is $count. " ;;
-e ) count=`grep ^e $2|wc –l` echo "The number of lines in $2 that start with an e is $count. " ;; * ) //默认匹配 echo "That option is not recognized. " ;; esac //和case成对出现 #end
将其存为case_1,然后执行chmod a+x case_1。 执行程序case_1: [root@redflag /root]# ./case_1 –i file1 The number of lines in file1 that start with an i is 8.
【实例 14】 此实例使用case语句建立一个菜单,这也是case最为常见的一种应用。该实例源代码如下: #!/bin/bash #display a menu echo "----------" echo "1 Restore"