玖叶教程网

前端编程开发入门

LINUX shell 基础编程介绍(linux的shell编程)

【十二】shell 编程

12.1 Shell 环境概述

Shell 的作用:命令解释器,“翻译官”。介于操作系统内核与用户之间,负责解释命令行。

Shell 环境的切换:

1)登录Shell

/etc/shells 文件记录了系统支持的有效登录Shell

[root@alex ~]# cat /etc/shells

2)切换Shell环境

临时切换:直接执行其他Shell程序,示例ksh、zsh等。

更改用户登录Shell:

需修改 /etc/passwd 文件中用户记录的最后一个字段

或执行:usermod -s Shell程序路径 用户名

3)查看缺省的shell

[root@alex ~]# echo $SHELL

/bin/bash

【Bash的历史命令】

1)保存用户曾经执行过的命令操作

存放位置:~/.bash_history 文件

2)查看历史命令

使用↑、↓按键逐条翻看,允许编辑并重复执行

3)执行:history

清除历史命令history -c

4)调用历史命令

!n:执行历史记录中的第n条命令

!str:执行历史记录中最近一次以“str”开头的命令【这个有用

设置历史命令能够输出的记录数,修改 HISTSIZE 参数(默认为1000条) 【这个环境变量在/etc/profile里】。

Bash的命令别名:为使用频率较高的复杂命令行设置简短的调用名称

存放位置:~/.bashrc

查看命令别名:格式:alias [别名]

如:alias sqlplus='rlwrap sqlplus'

取消已设置的命令别名 格式:unalias 别名

【注】:.bashrc会被.bash_profile调用,所以也可以将别名写到.bash_profile中。

11.2 Shell变量应用

变量的种类:

Shell变量是用来代表某个值的符号名,变量是shell传递数据的一种方法。为灵活管理,Linux系统提供特定参数,有两层意思:

变量名:使用固定的名称,由系统预设或用户定义

变量值:能够根据用户设置、依系统环境变化而变化

Shell变量的种类:

1)用户自定义变量:由用户自己定义、修改和使用

2)环境变量:由系统维护,用于设置用户的Shell工作环境,只有极少数的变量用户可以修改

3)预定义变量:Bash预定义的特殊变量,不能直接修改

4)位置变量:通过命令行给脚本传递执行参数

用户自定义变量:

定义新的变量:变量名要以英文字母或下划线开头,区分大小写

格式:变量名=变量值

查看变量的值:

格式:echo $变量名

在使用变量值时,要在变量名前加上前缀“$”。

示例①:

[root@alex ~]# abc='hello world'   字符串中有空格要使用引号
[root@alex ~]# echo $abc

hello world

[root@alex ~]# unset abc 删除变量

变量值可以作为某个长字符串中的一部分。如果它在长字符串的末尾,就可以利用直接引用形式,如果变量的值须出现在长字符串的开头或中间,避免shell把它与其他字符混在一起,则应该用花括号将变量名括起来。

示例②:

[root@alex ~]# abc=china
[root@alex ~]# echo www.$abc.com

www.china.com

[root@alex ~]# echo www.$abcalex.com

www..com

[root@alex ~]# echo www.${abc}alex.com

www.chinaalex.com

从键盘输入内容为变量赋值:

格式: read [-p “提示信息"] 变量名

结合不同的引号为变量赋值:

双引号 “ ” :允许通过$符号引用其他变量值

单引号 ‘ ’ :禁止引用其他变量值,$视为普通字符

示例③

[root@alex ~]# vi alex1.sh
#!/bin/bash
x=abc
printf "x is now $x. Enter new value: " $x
read x
echo $x

【注】:printf是一个函数

验证:

[root@alex ~]# sh alex1.sh

x is now abc. Enter new value: xyz

xyz

倒引号 ` ` :将命令执行的结果输出给变量

示例④:

[root@alex ~]# find /dev -type p

/dev/initctl

[root@alex ~]# ls -l `find /dev -type p`

prw------- 1 root root 0 01-30 13:02 /dev/initctl

【环境变量】

Shell有两类变量:临时变量和全局变量

临时变量是shell程序内部定义的,其使用范围仅限于定义它的程序,对其它程序不可见。包括:用户自定义变量、位置变量和预定义变量。

全局变量是环境变量,其值不随shell脚本的执行结束而消失。把一个Shell变量用EXPORT命令导出,就创建了环境变量。它们对于以后在该Shell下执行的所有程序都是可见的。

设置环境变量PATH:

常用命令的目录放在PATH变量中,使用频度高命令的目录排在前面;尽量避免查询大目录,如需设置,将其路径放在PATH路径的最后位置。

例:PATH=/bin:/usr/bin:/etc:/:.

位置变量(参数)

在执行Shell脚本时,可以定义最多9个位置参数,表示为$n,n为1~9之间的数字。

预定义变量:表示形式如下。

$#:命令行中位置参数的数量

$*:所有位置参数的内容

$?:上一条命令执行后返回的状态,当返回状态值为0时表示执行正常,非0值表示执行异常或出错

$:当前所在进程的进程号

$!:后台运行的最后一个进程号

$0:当前执行的进程/程序名

【Shell中的通配符】:

1)* 匹配任何字符串。

2)?匹配任何单个字符。

3)[...,-]匹配方括号所限定的任何一个字符【最终是方括符中某单个字符满足要求

示例:[a-d,x,y]是匹配单个字符【a、b、c、d、x、y单个字符满足要求

[!Z] 是匹配不是Z的所有单个字符

4)\ 转意符,使原字符失去其特殊的含义。

基本的算数运算:计算整数表达式的运算结果

格式:expr 变量1 运算符 变量2 ...[运算符 变量n]

expr的常用运算符:

加法运算:+

减法运算: -

乘法运算: \*

除法运算: /

求模(取余)运算: %

[root@alex ~]# a=1
[root@alex ~]# b=2
[root@alex ~]# c=`expr $a + $b` 运算符号两端要空格
[root@alex ~]# echo $c

3

[root@alex ~]# c=`expr \( $a + $b \) \* $b` 运算符号两端要空格,并且()和*都要使用转意符“\”
[root@alex ~]# echo $c

6

使用let命令格式更友好,但有些Shell不支持。

[root@alex ~]# let c=a+b
[root@alex ~]# echo $c

3

[root@alex ~]# let c=(a+b)*b
[root@alex ~]# echo $c

6

【逻辑操作符】:

1)逻辑与&&:可以把两个命令联系在一起

形式:命令1 && 命令2

功能:先运行命令1,如果成功,才运行命令2,否则不运行命令2

2)逻辑或||:命令互补

形式:命令1 || 命令2

功能:先运行命令1,不成功运行命令2,否则不运行命令2.

试比较下面的例子:

[root@alex ~]# ls -l;date;uptime;LS;ls
[root@alex ~]# ls -l&&date&&uptime&&LS&&ls
[root@alex ~]# ls -l||date||uptime||LS||ls
[root@alex ~]#LS||date||uptime||LS||ls LS不成功,补date

【成组命令】

在shell中可以使用2种方式将若干命令组合在一起,只返回一个逻辑结果。

使用花括号{}

使用圆括号()

以花括号括起来的命令可视为语法上的一条命令。成组命令的执行顺序是根据命令出现的先后次序,由左向右执行。

在使用花括号时在格式上应注意,左括号“{”后面应有一个空格;右括号“}”之前应有一个分号“;”。

在使用(){} 也可以包含若干单独占一行的命令。

[root@alex ~]# vi alex2.sh
#!/bin/bash
Parent="P"
echo Before: $Parent
{
Parent="C"
echo After: $Parent
}
echo After: $Parent

验证:

[root@alex ~]# sh alex2.sh

Before: P

After: C

After: C

把{}换成()后

[root@alex ~]# sh alex2.sh

Before: P

After: C

After: P

用圆括号括起来的成组命令是在新的子shell内执行,由于不属于同一进程,因此,在圆括号内的命令不会改变父 shell的变量值及工作目录。

12.3 编写并执行Shell脚本(一)

【Shell脚本概念】:

用途:完成特定的、较复杂的系统管理任务

格式:集中保存多条Linux命令,普通文本文件

执行方式:按照预设的顺序依次解释执行。

【脚本文件的内容】:

运行环境设置:#!/bin/bash 这句不是注释,它告诉系统后面的shell要用bash解释

注释信息:以#开始的说明性文字,可执行的Linux命令行。

【脚本的可执行权限】:

1)直接执行具有“x”权限的脚本文件

示例:./repboot.sh

2)使用指定的解释器程序执行脚本内容

示例:bash repboot.sh、sh repboot.sh

3)通过source命令(或 . )读取脚本内容执行

示例:souce repboot.sh 或 . Hello.sh

12.4 编写并执行Shell脚本(二)

12.4.1条件测试操作

【测试命令test】

用途:测试特定的表达式是否成立,当条件成立时,命令执行后的返回值为0,否则为其他数值

格式:test 条件表达式

[ 条件表达式 ]

常见的测试类型:①测试文件状态②整数值比较③字符串比较④逻辑测试

条件测试-测试文件

测试文件状态

格式:[ 操作符 文件或目录 ]

常用的测试操作符:

-d:测试是否为目录(Directory)
-e:测试目录或文件是否存在(Exist)
-f:测试是否为文件(File)
-r:测试当前用户是否有权限读取(Read)
-w:测试当前用户是否有权限写入(Write)
-x:测试当前用户是否可执行(Excute)该文件
-L:测试是否为符号连接(Link)文件

条件测试-整数值比较

整数值比较

格式:[ 整数1 操作符 整数2 ]

常用的测试操作符

-eq:等于(Equal)

-ne:不等于(Not Equal)

-gt:大于(Greater Than)

-lt:小于(Lesser Than)

-le:小于或等于(Lesser or Equal)

-ge:大于或等于(Greater or Equal)

条件测试-字符串比较

字符串比较

格式:[ 字符串1 = 字符串2 ]

[ 字符串1 != 字符串2 ]

[ -z 字符串 ]

常用的测试操作符

=:字符串内容相同

!=:字符串内容不同,! 号表示相反的意思

-z:字符串内容为空

条件测试—逻辑测试

逻辑测试

格式:[ 表达式1 ] 操作符 [ 表达式2 ] ...

常用的测试条件的逻辑操作符

!逻辑非(NOT),它放在任意逻辑表达式之前,使原来的表达式由真变假,或者由假变真。

例如:[ ! -r $1 ] 另一种写法!test -r “$1” 这句相当于说$1的内容非可读才是真

-a或&&:逻辑与,“而且”的意思,

前后两个表达式都成立时整个测试结果才为真,否则为假

例如:[ -f “$myfile” -a -r “$myfile” ] $myfile即是文件又可读才是真,否则为假

-o或||:逻辑或,“或者”的意思

操作符两边至少一个为真时,结果为真,否则结果为假

例如:[ “$a” -ge 0 -o “$b” -le 100] 假如$a=5整个结果就是真了。有一个为真就是真

()圆括号,把一个逻辑表达式括起来,使之优先得到运算,缺省下-a 的优先级高于-o,()可以改变这种优先级

12.4.2使用if条件语句

通常,if的测试部分是利用test命令或[]实现的。其实,条件测试可以利用一般命令执行成功与否来作判断。如果命令正常结束,则表示执行成功,其返回值为0,条件测试为 真,如果命令执行不成功,其返回值不等于0,条件测试就为假。如果,各命令表可以由一条或者多条命令组成,那么测试条件以其最后一条命令是否执行成功为准。

单分支:当“条件成立”时执行相应的操作

双分支:当“条件成立”、“条件不成立”时执行不同操作

多分支:相当于if语句嵌套,针对多个条件执行不同操作

示例:

[root@alex ~]# vi finduser.sh
#!/bin/bash
if [ $# -ne 1 ]
then
echo Usage: please input single username >&2
exit 1
fi
who | grep $1

【注】:>&2表示把标准输出和错误输出都定向到终端上

[root@alex ~]# bash finduser.sh root 一个位置参数

root pts/0 2016-02-01 08:52 (192.168.3.100)

[root@alex ~]# bash finduser.sh root oracle 两个位置参数时没有结果

Usage: finduser username

[root@alex ~]# echo $?

1 exit返回值是1

12.4.3使用循环语句

一)For循环

根据变量的不同取值,重复执行一组命令操作

For语句有三种格式,不同在于in的后面可以跟

For 变量 in 值表

For 变量 in 文件正则表达式

For 变量 in 命令行的位置参数

示例1:for语句使用值表。计算1 3 5 7 9的和;并且输出当前目录下的所有.sh文件。

[root@alex ~]# vi forapp1.sh
#!/bin/bash
result=0
for i in 1 3 5 7 9
do
let result=result+i
done
echo "result = $result"
###
j=1
for file in *.sh
do
echo "The ${j}th file is: $file"
j=`expr $j + 1`
done

验证

[root@alex ~]# bash forapp1.sh

示例2:for语句使用位置参数。显示所有位置参数

[root@alex ~]# vi forapp2.sh
#!/bin/bash
j=1
for i in $*
do
echo "The ${j}th parameter is: $i"
let j=j+1
done

验证

[root@alex ~]# bash forapp2.sh p1 p2

The 1 th parameter is: p1

The 2 th parameter is: p2

二)While循环语句

重复测试指定的条件,只要条件成立则反复执行对应的命令操作

示例1:whileapp1脚本:求1到10的和

[root@alex ~]# vi whileapp1.sh
#!/bin/bash
x=1
result=0
while [ $x -le 10 ]
do
let result=result+x
let x=x+1
done
echo $result

验证

[root@alex ~]# sh whileapp1.sh

55

示例2:

批量添加20个系统用户帐号, 用户名依次为“stu1”、“stu2”、……、“stu20”,这些用户的初始密码均设置为“123456”

#vi adduser.sh
#!/bin/bash
i=1
while [ $i -le 20 ]
do
useradd stu$i
echo "123456" | passwd --stdin stu$i &> /dev/null
i=`expr $i + 1`
done

应用示例2:批量删除上例中添加的20个系统用户帐号

# vi deluser.sh i
#!/bin/bash
i=1
while [ $i -le 20 ]
do
userdel -r stu$i
i=`expr $i + 1`
done

三)Until循环

until语句根据条件执行重复操作

形式:

Until 测试条件

do

命令表

done

它与while语句很相似,只是测试条件不同;当测试条件为假时,才进入循环体,直至测试条件为真时终止循环。

示例:

1)添加一个tim用户,并授予密码

[root@alex ~]# useradd tim
[root@alex ~]# passwd tim

2)编写untilapp1.sh脚本:等待某个用户(tim)登录,每20秒确定一次

[root@alex ~]#vi untilapp1.sh
#!/bin/bash
printf "Enter username: "
read user
until who | grep $user > /dev/null
do
sleep 20
done
echo "$user have logged in"

3)执行该脚本会一直处于执行状态

[root@alex ~]#sh untilapp1.sh

Enter username: tim

4)在主控台让tim登录,则该脚本才会执行完成。

Enter username: tim

tim have logged in

12.4.4 CASE语句

CASE语句

根据变量的不同取值,分别执行不同的命令操作,Case语句允许进行多重条件选择。语法形式如下:

case 字符串 in

正则表达式1)命令

命令;;

正则表达式2)命令

命令;;

正则表达式n)命令

命令;;

esac

使用case语句应注意:

1)每个正则表达式后面可以有一条或多条命令,其最后一个命令必须以;结束,Exit命令后可以不要。

2)正则表达式中可以使用通配符。

3)如果一个正则表达式是由多个模式组成,那么各模式之间应以竖线 (|)隔开,表示各模式是“或”的关系,即只要给定字符串与其中一个模式相配,就会执行其后的命令表。

4)各正则表达式应是唯一的,不应重复出现。并且要合理安排正则表达式的出现顺序。例如,不应将“*”作为头一个正则表达式。因为与任何字符串匹配,它若第一个出现,就不会再检查其他表达式了。

5)Case的退出(返回)值是整个结构中最后执行的那个命令。若没有执行任何命令,则退出值为零。

示例:

[root@alex ~]# vi caseapp.sh
#!/bin/bash
name=`basename $0 .sh`
case $1 in
s|start)
echo "start..."
;;
stop)
echo "stop..."
;;
reload)
echo "reload..."
;;
*)
echo "Usage: $name [start|stop|reload]"
exit 1
;;
esac
exit 0

【注】:basename这里就是取得不带路径的执行的shell脚本的名称, 扩展名.sh也会去掉。

例如:# basename /root/test/finduser.sh .sh

finduser

验证

[root@alex ~]# sh caseapp.sh s

start...

[root@alex ~]# sh caseapp.sh start

start...

[root@alex ~]# sh caseapp.sh stop

Stop...

[root@alex ~]# echo $?

0

[root@alex ~]# sh caseapp.sh abc

Usage: caseapp [start|stop|reload]

[root@alex ~]# sh caseapp.sh

Usage: caseapp [start|stop|reload]

[root@alex ~]# echo $?

1

SHIFT 语句:

位置参数最多不能超过9个,即$1~$9。如果实际给定的 命令行参数多于9个,就需要用shift命令移动位置参数。每执行一次 shift 命令,就把位置参数向左移一位,新的$1的值是原来$2的值,新 $2 是原来$3的值,依次类推。

Shift 命令不能把$0移走。Shift 命令可以带有一个整体作为参数。如果没有带参数默认是1

示例:

[root@alex ~]# vi shiftapp1.sh
#!/bin/bash
#loop=0
while [ $# -ne 0 ]
do
echo $1
done

# 修改权限,让其可执行

[root@alex ~]# chmod u+x shiftapp1.sh

# 执行

[root@alex ~]# ./shiftapp1.sh p1 p2 p3

结果:死循环,而不是将所有的参数输出后结束。

#!/bin/bash
#loop=0
while [ $# -ne 0 ]
do echo $1
shift
done
[root@alex ~]# ./myapp1.sh p1 p2 p3

p1

p2

p3...

如果改成shift 2如何

【循环控制语句】:break语句

在for、while、until等循环语句中,用于跳出当前所在的循环体,执行循环体后的语句

continue

在for、while、until等循环语句中,用于跳过循环体内余下的语句,重新判断条件以便执行下一次循环

Shell函数应用:

在编写Shell脚本程序时,将一些需要重复使用的命令操作,定义为公共使用的语句块,即可称为函数,合理使用Shell函数,可以使脚本内容更加简洁,增强程序的易读性,提高执行效率。

应用示例:

在脚本中定义一个加法函数,名叫adder,用于计算2个整数的求和

调用该函数计算(12+34)、(56+789)的和

[root@alex ~]# vi addderfun.sh
#!/bin/bash
adder() {
echo `expr $1 + $2`
}
adder 12 34
adder 56 789

验证

[root@alex ~]# sh adderfun.sh

46

845



the end !!!

@jackman 共筑美好!

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言