Shell 编程基础

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shell 编程基础相关的知识,希望对你有一定的参考价值。

Shell脚本的关键在于输入多个命令并处理每个命令的结果,甚至需要将一个命令的结果传给另一个命令。Shell可以让你将多个命令串起来,一次执行完成。

基本格式:

第一行必须为固定格式,指明脚本使用哪种shell来运行脚本,通常shell脚本中会以 # 作为注释,注释号后面的内容不会参与脚本的运行,但是,第一行是个例外。

技术分享图片技术分享图片

变量命名法则:

1、不能使程序中的保留字:例如if, for

2、只能使用数字、字母及下划线,且不能以数字开头,不能使用 - (减号)

正确:_abc123 ;  abc123 ; abc_123

错误:var1-abc=100  ;  var1-123=100  ;  -var1=100

3、见名知义

name  ,date

4、统一命名规则:驼峰命名法

HostName


直接运行脚本的时候,会新开一个shell进程,脚本中默认关闭了alias功能

局部变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效。

环境(全局)变量:生效范围为当前shell进程及其子进程

本地变量:生效范围为当前shell进程中某代码片断,通常指函数

位置变量:$1, $2,$N ...来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数

特殊变量:

$?

返回上一条命令执行状态

$0

命令本身

$*

传递给脚本的所有参数,全部参数合为一个字符串,用双括号括起

[email protected]

传递给脚本的所有参数,每个参数为独立字符串,每个都用双括号括起

$#

传递给脚本的参数的个数

$_

上个命令的最后一个参数

$$

显示当前进程号

$PPID

显示父进程号

$!

上一个子进程的进程号

$-

在Shell启动或使用set命令时提供选项

$n

位置参数值,n表示位置

使用pstree -p 查看进程树

[email protected] $* 只在被双引号包起来的时候才会有差异


变量赋值:

变量名=值

赋值等号与值之间没有空格

[中括号里写变量的时候,记得加双引号]

(1) 可以是直接字串; 变量名=root  

如果值为带空格或特殊字符时,请使用双引号和  \  转义符号

(2) 变量引用:     变量名="$USER"

(3) 命令引用:    变量名=`指令`

变量名=$(指令)

变量引用:

${变量名}

$变量名

"双引号":弱引用,其中的变量引用会被替换为变量值

'单引号':强引用,其中的变量引用不会被替换为变量值,而保持原字符串

显示已定义的所有变量

set

删除变量:

unset 变量名

只读变量:只能声明,但不能修改和删除

声明只读变量:

readonly 变量名

declare -r 变量名

查看只读变量:

readonly –p

位置变量:在脚本代码中调用通过命令行传递给脚本的参数


set -- 清空所有位置变量


进程使用退出状态来报告成功或失败

一般来讲,

0 代表成功,1-255代表失败

以下表为在未自定义退出状态码(exit)时的常见,可以参考

状态码

描述

0

命令成功结束

1

一般性未知错误,可能是无效参数

2

不适合的shell命令

126

命令不可执行

127

没有找到命令

128

无效的退出参数

128+x

与Linux信号x相关的严重错误

130

通过Ctrl+C终止的命令

255

正常范围之外的退出状态码


bash自定义退出状态码

exit [n]:自定义退出状态码

脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字

如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

退出状态可以使用变量作为值,退出状态码最大值为255,如果值超过255时,将会通过

取模运算  值/256 把状态码缩减到0~255整数值之间,比如:

exit 300

300/256 取模=44    400/256 取模=144


bash自带脚本测试

bash -n 语法检查

bash -x  脚本执行按步调试

技术分享图片


算术运算

+

两个整数相加


%

两整数相除,取余数

-

第一个数减去第二个数




*

两整数相乘




\

第一个整数除以第二个整数




实现算术运算的方法:

(1) let 变量名=算术表达式

(2) var=$[算术表达式]

sum=$[uid10+uid20]

sum=$[$uid10+$uid20]

(3) var=$((算术表达式))

sum=$((uid10+uid20))

(4) declare –i 变量名 = 数值

(5) echo ‘算术表达式’ | bc


条件测试

若真,则返回0

若假,则返回1

1. test 语句

2. [空格 表达式 空格]

推荐使用第2种方法,因为我们去看系统本身自带的脚本编写使用的正是这一类方法。

第一个 [ 之后和第二个 ] 之前必须加上一个空格,否则会报错

技术分享图片

技术分享图片

上面的中括号是错误的格式,会报以下的错误

技术分享图片

技术分享图片

++++++++++++我是华丽的分界线++++++++++++++++++++

技术分享图片

技术分享图片

上面的中括号是错误的格式,会报以下的错误

技术分享图片

技术分享图片

++++++++++++我是华丽的分界线++++++++++++++++++++

以下才是正确的格式

技术分享图片

技术分享图片

可以判断4类条件

a.数值测试 b.字符串测试 c.文件测试 d.布尔逻辑组合测试条件


以下逐个看

a.数值测试

可以用在数字和变量(变量值是数字)上

-lt

小于

less than


-eq

等于 equal

-gt

大于

great than


-ne

不等于

not equal

-ge

大于等于

great equal




-le

小于等于

less equal




注意,当碰到系统特殊符号的时候,记得 \ 转义

技术分享图片

技术分享图片

技术分享图片

技术分享图片

但是涉及到浮点值的时候,数值测试会有一个限制 ,我们来看一个例子:

技术分享图片

技术分享图片

变量$var1的值是浮点值,脚本对这个值进行了测试,显然这里就报错。因此,请记住

bash shell只能处理整数(zshell能很好的解决这个问题),当然,如果这个值只是用来

echo 输出是没问题的。

技术分享图片

技术分享图片

技术分享图片

技术分享图片

因此,此时shell的退出状态码也是为非0值了,也就是执行了else 之后的语句。


b.字符串测试

相等比较

在比较字符的相等性时,会将所有的标点和大小写情况都考虑在内的

==

字符串是否相同


-n 字符串

字符串是否为非0

!=

字符串是否不同


-z 字符串

字符串是否为0

<

左边的ascii码是否小于右边的ascii码


=~

左侧字符串是否能够被

右侧的表达式所匹配

用于[[ 双中括号中 ]]

>

左边的ascii码是否大于右边的ascii码






技术分享图片

技术分享图片

使用调试工具来直观的看出状态码与结果

技术分享图片

技术分享图片

使用=或者==  ,或者"" 和"空格" 的结果都是一致的

技术分享图片

技术分享图片

技术分享图片

技术分享图片

使用单引号也是一致的

技术分享图片

技术分享图片

这里需要注意的是,当值中带有空格的时候,变量没有双引号引起来会是报错的

技术分享图片

技术分享图片

当变量双引号引起来的时候,

技术分享图片

技术分享图片

正确输出

技术分享图片

技术分享图片

所以,在写 bash 脚本的时候,别偷懒,对于变量的引用最好都加上双引号!就变量引用上来说,虽然 zsh 在这点要强过 bash,但是处于兼容性的考虑,还是把双引号带上吧。


字符的比较

先来一个初学者常犯的错误

技术分享图片

技术分享图片

乍一看,没问题啊

技术分享图片

技术分享图片

可以当然我们使用ls查看当前目录的时候,发现$var2的值被重定向至以$var2的值,也就是abcdA的文件中了。这是一个不易觉察的严重问题。脚本把 > 解析成了重定向输出符号。同时,因为重定向成功,因此exit退出码为0,就会执行then语句了。

因此,使用 双引号 引起来 或 \ 转义解决吧。

技术分享图片

技术分享图片

这才是规范的脚本写法,别掉坑了哦~~

技术分享图片

技术分享图片

这才是正确的输出结果

技术分享图片

技术分享图片

字符串的大小写比较

技术分享图片

技术分享图片

在Shell的比较测试中,大写字母是被认为是小于小写字母的。这一点与sort命令恰好相反,同样的字符串用sort排序时,小写字母先出现,这是由于各个命令使用的排序技术不同造成的。

技术分享图片

技术分享图片

因此,总结为2句话:

shell编程时,小写字母 >(大于) 大写字母

sort排序时,小写字母  >(优先) 大写字母

如果出现以下大小写混合并相同的情况呢

技术分享图片

技术分享图片

那么就从左边开始比,第一位a相同,那就比第一位,b > A  根据以前的总结,结果就是

$var1 > $var2,不信就以图验证下

技术分享图片

技术分享图片

而sort命令则是以按小写字母>相同的大写字母排序的,注意哦~

技术分享图片

技术分享图片

如果是把数值的比较用了字符串的比较,那么你会怀疑你的数学是体育老师教的吧

技术分享图片

技术分享图片

数字越大就是大

技术分享图片

技术分享图片

最后的总结,如果使用错了操作符,可能无法得到正确的结果。

比较类型

使用的操作符

数值

-lt; -gt; -le; -ge; -eg; -ne

字符串

=; !=; >; <;

检查变量是否含有数据

-n 就是判断字符串是否为0

技术分享图片

技术分享图片

结果

技术分享图片

技术分享图片

++++++++++++我是华丽的分界线++++++++++++++++++++

技术分享图片

技术分享图片

结果

技术分享图片

技术分享图片

++++++++++++我是华丽的分界线++++++++++++++++++++

技术分享图片

技术分享图片

结果

技术分享图片

技术分享图片

++++++++++++我是华丽的分界线++++++++++++++++++++

技术分享图片

技术分享图片

结果,同时用双引号引起来的 空格 也是一样的结果

技术分享图片

技术分享图片

++++++++++++我是华丽的分界线++++++++++++++++++++

技术分享图片

技术分享图片

结果,没有定义就是0,就是没有值

技术分享图片

技术分享图片

++++++++++++我是华丽的分界线++++++++++++++++++++

-z 就是判断字符串是否为0

技术分享图片

技术分享图片

结果,与-n选项的结果是一致的

技术分享图片

技术分享图片

++++++++++++我是华丽的分界线++++++++++++++++++++

技术分享图片

技术分享图片

结果,用单引号引起来的 空格,结果也是一样的,与-n的结果是一致的

技术分享图片

技术分享图片

++++++++++++我是华丽的分界线++++++++++++++++++++

技术分享图片

技术分享图片

结果,用单引号引起来的的什么也没有,结果也是一样的,与-n的结果是一致的

技术分享图片

技术分享图片

++++++++++++我是华丽的分界线++++++++++++++++++++

技术分享图片

技术分享图片

结果,与-n 的结果是一致的

最后的总结,不管是单双引号引用的没有值变量,或者没有被声明的变量,值都是0.也就是空。

空和未初始化的变量会对shell脚本测试造成灾难性的影响,如果不是很确定一个变量的内容,最好在将其用于数值或字符串比较之前先通过- n 或 -z 来测试下变量是否含有值。

最后最后的警示演示:

清除下历史记录

#history -c

技术分享图片

技术分享图片

执行脚本,我的天啊,我的脚本原本的意图只是想删除/app/下面的全部文件而已,怎么变成了删除根目录下面的全部文件夹了呢!!太吓人了啊~~脚本有风险,且行且珍惜。哈哈~~

技术分享图片

技术分享图片

c.文件测试

用来测试Linux文件和目录的状态。

(选项后接file名,比如 -e file  )


存在性测试

-e

文件存在性测试,存在为真,否则为假



存在性及类别测试

-b

是否存在且为块设备文件

-c

是否存在且为字符设备文件

-d

是否存在且为目录文件

-f

是否存在且为普通文件

-L(大写)

存在且为符号链接文件

-p

是否存在且为命名管道文件

-S(大写)

是否存在且为套接字文件



文件权限测试

-r

是否存在且可读

-w

是否存在且可写

-x

是否存在且可执行



文件特殊权限测试

-u

是否存在且拥有suid权限

-g

是否存在且拥有sgid权限

-k

是否存在且拥有sticky权限



文件大小测试

-s(小写)

是否存在且非空



文件是否打开测试

-t fd

fd文件描述符是否在某终端已经打开

-N

文件自从上一次被读取之后是否被修改过

-O

当前有效用户是否为文件属主

-G

当前有效用户是否为文件属组,只会检查默认的主组,而不检查附加组

所谓的有效用户就是指,使用特殊的suid权限时,运行此程序的用户



双文件测试

File1 -ef File2

File1是否是File2的硬链接

File1 -nt File2

File1是否新于File2(mtime)。必须确认文件是存在的,否则会返回错误结果

File1 -ot File2

File1是否旧于File2(mtime)。必须确认文件是存在的,否则会返回错误结果

因为这些操作符比较统一规范,自己多练习就好了,我就只给2个例子:

技术分享图片

技术分享图片

d.布尔逻辑组合测试条件

&&

并且(AND),操作符2边的条件同时必须满足才会执行后面的指令,2个条件组合成为真

[[ 条件1 && 条件2 ]]

test模式下使用-a

||

或者(OR),操作符2边的条件只能满足其中一个才会执行后面的指令,2个条件组合成为假

[[ 条件1 || 条件2 ]]

test模式下使用-o

!

! 条件

第一种方式:双中括号格式

如:[[ -r FILE ]] && [[ -w FILE ]]

[[ -r FILE ]] || [[ -w FILE ]]

第二种方式:必须使用测试命令test进行

如:test [ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab

test [ -f /bin/cat -o -x /bin/cat ] && cat /etc/fstab


高级特性

bash shell 提供了2项可在if-then语句中使用的高级特性:

a.用于数学表达式的双括号 ((  ))

不需有将双括号中表达式里的运算符转义

建议括号内2边加空格

((空格 表达式  空格))

b.用于高级字符串处理功能的双中括号 [[  ]]

不是所有的shell都支持双中括号

建议双中括号内2边加空格

[[空格 表达式  空格]]

操作符号

va1++

先运算,后自增1


!

逻辑求反

va1--

先运算,后自减1


~

位求反

++va1

先自加1,后运算


**

幂运算

--va1

先自减1,后运算


<<

左位移

&

位布尔和


>>

右位移

|

位布尔或


&&

逻辑和

=~

双中括号中后面跟

扩展正则表达式


||

逻辑或

va1++  (va1--)

自身先和后面的运算式运算,表达式的结果跟自身没有任何关系,再自身+-1的值赋与以后使用。

例子: a=5 b=2

a++ +b=7   (a+b=7,此时a的值为6)

上条表达式后的下一条表达式a的值已经变化了

a+b=8


++id ( --id)

例子: a=5 b=2

++a +b =8  (a+1=6,6+b=8,此时a的值为6)

上条表达式后的下一条表达式a的值已经变化了

a+b=8

自身先+-1,再和后面的运算式运算,表达式的结果跟自身没有任何关系,

以后的值就是原先自身先+-1


双括号范例

技术分享图片技术分享图片

双中括号范例,扩展正则表达式

技术分享图片技术分享图片

双中括号范例,扩展正则表达式

技术分享图片技术分享图片

技术分享图片

技术分享图片

如果写成双等号的话,双中括号会自动转化为带转义的写法

技术分享图片技术分享图片

注意红框的地方

技术分享图片技术分享图片


第一章节到此结束,本人水平有限,如有错漏地方,欢迎指正。


以上是关于Shell 编程基础的主要内容,如果未能解决你的问题,请参考以下文章

shell编程基础

Shell脚本编程基础

第九章shell脚本编程基础

SHELL脚本编程基础

第17篇 shell编程基础

编程语言和shell编程基础