Shell 编程基础(一)

简介:

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

基本格式:

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

1.png

变量命名法则:

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

命令本身

$*

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

$@

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

$#

传递给脚本的参数的个数

$_

上个命令的最后一个参数

$$

显示当前进程号

$PPID

显示父进程号

$!

上一个子进程的进程号

$-

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

$n

位置参数值,n表示位置

使用pstree -p 查看进程树

$@ $* 只在被双引号包起来的时候才会有差异


变量赋值:

变量名=值

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

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

(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.png


算术运算

+

两个整数相加


%

两整数相除,取余数

-

第一个数减去第二个数




*

两整数相乘




\

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




实现算术运算的方法:

(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种方法,因为我们去看系统本身自带的脚本编写使用的正是这一类方法。

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

3.png

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

4.png

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

5.png

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

6.png

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

以下才是正确的格式

7.png

可以判断4类条件

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


以下逐个看

a.数值测试

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

-lt

小于

less than


-eq

等于 equal

-gt

大于

great than


-ne

不等于

not equal

-ge

大于等于

great equal




-le

小于等于

less equal




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

8.png

9.png

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

10.png

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

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

echo 输出是没问题的。

11.png

12.png

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


b.字符串测试

相等比较

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

==

字符串是否相同


-n 字符串

字符串是否为非0

!=

字符串是否不同


-z 字符串

字符串是否为0

<

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


=~

左侧字符串是否能够被

右侧的表达式所匹配

用于[[ 双中括号中 ]]

>

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






13.png

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

14.png

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

1.png

1.png

使用单引号也是一致的

1.png

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

1.png

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

1.png

正确输出

1.png

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


字符的比较

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

1.png

乍一看,没问题啊

1.png

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

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

1.png

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

1.png

这才是正确的输出结果

1.png

字符串的大小写比较

1.png

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

1.png

因此,总结为2句话:

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

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

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

1.png

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

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

1.png

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

1.png

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

1.png

数字越大就是大

1.png

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

比较类型

使用的操作符

数值

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

字符串

=; !=; >; <;

检查变量是否含有数据

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

1.png

结果

1.png

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

1.png

结果

1.png

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

1.png

结果

1.png

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

1.png

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

1.png

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

1.png

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

1.png

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

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

1.png

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

1.png

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

1.png

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

1.png

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

1.png

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

1.png

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

1.png

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

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

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

最后最后的警示演示:

清除下历史记录

#history -c

1.png

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

1.png

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个例子:

1.png

2.png

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


双括号范例

spacer.gif1.png

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

spacer.gif1.png

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

spacer.gif1.png

1.png

spacer.gif

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

spacer.gif1.png

注意红框的地方

spacer.gif1.png


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




本文转自 ljpwinxp 51CTO博客,原文链接:http://blog.51cto.com/191226139/2044393
相关文章
|
2月前
|
Ubuntu Linux Shell
【Linux操作系统】探秘Linux奥秘:shell 编程的解密与实战
【Linux操作系统】探秘Linux奥秘:shell 编程的解密与实战
59 0
|
6天前
|
监控 Shell 开发工具
Shell编程
Shell编程
|
26天前
|
存储 Java Shell
bigdata-04-shell编程基础
bigdata-04-shell编程基础
12 0
|
28天前
|
Shell Linux C++
【Shell 编程设计】 编写自己的清理后台的Shell脚本
【Shell 编程设计】 编写自己的清理后台的Shell脚本
30 1
|
28天前
|
存储 Shell 数据安全/隐私保护
【Shell 编程指南】Shell read命令 (从标准输入读取数值)
【Shell 编程指南】Shell read命令 (从标准输入读取数值)
22 0
|
28天前
|
Shell C语言 C++
【Shell 编程指南】shell中的(),{}几种语法用法
【Shell 编程指南】shell中的(),{}几种语法用法
17 0
|
28天前
|
Shell 程序员 Linux
【Shell 编程指南】shell运算操作符之(())
【Shell 编程指南】shell运算操作符之(())
19 0
|
3月前
|
Shell
Shell 编程快速入门 之 函数基础知识
Shell 编程快速入门 之 函数基础知识
67 0
Shell 编程快速入门 之 函数基础知识
|
3月前
|
Shell Linux Perl
Shell 编程快速入门 之 字符串
Shell 编程快速入门 之 字符串
63 0
Shell 编程快速入门 之 字符串
|
3月前
|
Shell C语言 Perl
Shell 编程快速入门 之 循环结构详解
Shell 编程快速入门 之 循环结构详解
62 0
Shell 编程快速入门 之 循环结构详解