Shell脚本编程基础――Linux基本命令(11)

前端之家收集整理的这篇文章主要介绍了Shell脚本编程基础――Linux基本命令(11)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

1.Shell脚本基础

1shell脚本

包含一些命令或声明,并符合一定格式的文本文件

格式要求:首行shebang机制

#!/bin/bash

#!/usr/bin/python

#!/usr/bin/perl

2)格式要求

脚本代码开头约定:

1、第一行一般为调用使用的语言

2、程序名,避免更改文件名为无法找到正确的文件

3、版本号

4、更改后的时间

5、作者相关信息

6、该程序的作用,及注意事项

7、最后是各版本的更新简要说明(也可以不写)

wKiom1mJdZWQfwAFAAAy4gmIq3c921.png

其实最重要的是第一行,其他行也可以不写,但是为了一个良好的变成习惯,建议还是写上。

3)脚本调试

检测脚本中的语法错误

bash -n/path/to/some_script

调试执行

bash -x/path/to/some_script

wKioL1mJdZXSNnM9AAAdFSCDycs235.png

会一条一条的调试执行,可以找出哪一句错误

wKiom1mJdZbg0eoNAAA_Jm8gzRY786.png

如图,显示着最后一条有错误


2.变量

1)变量介绍

作用:

1、数据存储格式

2、参与的运算

3、表示的数据范围

类型:

字符

数值:整型、浮点型

变量命名法则:

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

2、只能使用数字、字母及下划线,且不能以数字开头

3、见名知义

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

2bash中变量的种类

根据变量的生效范围等标准:

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

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

局部变量:生效范围为当前shell进程中某代码片断(通常指函数)

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

特殊变量:$?,$0,$*,$@,$#,$$

3)本地变量

变量赋值:name=value

可以使用引用value:

(1) 可以是直接字串;name=root"

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

(3) 命令引用:name=`COMMAND` name=$(COMMAND)

变量引用:${name} $name

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

'':强引用,其中的变量引用不会被替换为变量值,而保

持原字符串

显示已定义的所有变量:set

删除变量:unset name

4)环境变量

变量声明、赋值:

export name=VALUE

declare -x name=VALUE

变量引用:$name,${name}

显示所有环境变量:

env

printenv

export

declare -x

删除变量:

unset name

bash内建的环境变量:

PATHSHELL USER UID HOME PWD SHLVL

LANG MAIL HOSTNAME HISTSIZE―

5)只读和位置变量

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

声明只读变量:

readonly name

declare -r name

查看只读变量:

readonly -p

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

$1,...:对应第1、第2等参数。$1表示第一个参数,$2表示第二个参数

wKioL1mJdZayM79oAABB5Qdm8vQ449.png

$0: 命令本身

$#: 传递给脚本的参数的个数

$*: 传递给脚本的所有参数,全部参数合为一个字符串

$@: 传递给脚本的所有参数,每个参数为独立字符串

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

假设你的脚本运行时你写了三个参数 分别存储在$1 $2 $3中

则"$*" 等价于 “$1 $2 $3 $4" ---》传递了一个参数

而“$@" 等价于 "$1" "$2" "$3" "$4" ---》传递了四个参数

wKiom1mJdZax2EguAABPT8lRxr0914.png

如图,分别使用两种方式将1 2 3 4传给aa.sh和bb.sh,然后取第一个参数,果然发现输出的结果表明$@传递了四个参数,因此取第一个才会是1。


set -- 清空所有位置变量

wKioL1mJdZeQZKbSAABMRQB6rao705.png

如图,使用set --后所有变量被清空

PS:引用一位数以上的变量(如上图的$10)时要加{},不然系统会认为是$10

wKiom1mJdZfi1lFfAABoEk_E3AA618.png

6)参数左移

shift n用于对参数的移动(左移)

wKioL1mJdZiQeSWWAAAv6Rzv3RM875.png

wKioL1mJdZjgaA9hAAA88gsMBIQ425.png

如图,参数向左移动了两位(就是删除最左边两个)。由abcdefg变成cdefg


3.退出状态

1退出状态

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

0 代表成功,1255代表失败

$? 变量保存最近的命令退出状态

wKiom1mJdZjBPnfYAAA67hq5MLE491.png

正常状态,$?值为0

wKioL1mJdr2RiXhxAABNcgf6LEE516.png

最后一条失败,$?值不为0

2自定义退出状态码

exit [n]

使用exit [n]也可以自定义退出状态码。注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字。

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


4.算术运算

bash中的算术运算:help let

+,-,*,/,%取模(取余),**(乘方)

实现算术运算:

(1) let var=算术表达式

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

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

(4) var=$(exprarg1 arg2 arg3 ...)

(5) declare �Ci var = 数值

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

乘法符号有些场景中需要转义。

bash有内建的随机生成器:$RANDOM0-32767

echo$[$RANDOM%50] 0-49之间随机

(同理可以使用echo$[$RANDOM%50+1]随机产生1-50之间的随机数)


5.赋值

增强型赋值:

+=,-=,*=,/=,%=

let varOPERvalue

例如:let count+=3

自加3后自赋值

自增,自减:

let var+=1

let var++

let var-=1

let var--


6.逻辑运算

1)与

真与真

真与假

假与真

假与假

总结:只要有一个假则为假

短路与:若前一个为假,则不再判断第二个值,因为结果必为假。

2)或

真或真真

真或假真

假或真真

假或假假

总结:只要有一个真则为真

短路或:若前一个为真,则不再判断第二个值,因为结果必为真。


7.条件测试

判断某需求是否满足,需要由测试机制来实现。专用的测试表达式需要由测试命令辅助完成测试过程。

评估布尔声明,以便用在条件性执行中

若真,则返回0

若假,则返回1

测试命令:

test EXPRESSION

[ EXPRESSION ]

[[ EXPRESSION ]]

注意:EXPRESSION前后必须有空白字符

wKioL1mJdr2RF4XKAAAYbJMrt1g774.png


根据退出状态而定,命令可以有条件地运行

&& 代表条件性的AND THEN

|| 代表条件性的OR ELSE

就是说如果前一条命令输出0,就执行&&后面的内容,否则执行||后面的内容

使用这种方法就不用每次使用$?调取结果了

wKiom1mJdr7zILlSAAAsYqJN4YE167.png


另外,使用[]可以判断是否有值,如有则输出0,如没有则输出1

wKioL1mJdr7xjNRVAAAfEVOGCJc524.png

wKioL1mJdr6A9xYCAAAwIbAMlts663.png


8.bash的测试

1)数值测试

-gt 是否大于

-ge 是否大于等于

-eq 是否等于

-ne 是否不等于

-lt 是否小于

-le 是否小于等于

wKiom1mJdr_wyKPhAABj5Dn92dc159.png

2)字符串测试

==是否等于

> ascii码是否大于ascii

< 是否小于

!=是否不等于

=~ 左侧字符串是否能够被右侧的PATTERN所匹配(部分内容被匹配即可)

注意: 此表达式一般用于[[ ]]中;扩展的正则表达式

wKioL1mJdr-TeHrGAAB5FkPFPvc809.png


-z "STRING 字符串是否为空,空为真,不空为假

-n "STRING 字符串是否不空,不空为真,空为假

注意:用于字符串比较时的用到的操作数都应该使用引号

3文件测试

使用方式为选项加文件-x FILE


存在性测试:

-a 判断文件存在则为真

-e-a

wKiom1mJdr-CRt01AAAqqfNhnWs711.png


存在性及类别测试:

-b判断文件为块设备文件则为真

-c判断文件为字符文件则为真

-d判断文件为目录文件则为真

-f判断文件为普通文件则为真

wKiom1mJdsDQT-3PAABHpBAwidw124.png


-h判断文件为软链接文件则为真

-L-h

wKioL1mJdsDxmvMUAACH7_MEmQw264.png

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

-S是否存在且为套接文件

文件权限测试:

-r判断当前用户对该文件可读时为真(root永远为真)

-w判断当前用户对该文件可写时为真(root永远为真)

-x判断当前用户对该文件可执行为真(只要有任意位置有xroot则为真)

文件特殊权限测试:

-u判断该文件suid权限为真(对于非二进制文件加上suid即使为真也无效)

-g判断该文件sgid权限为真(对于非二进制文件加上sgid即使为真也无效,目录有效)

-k判断文件是否有sticky权限(对于普通文件没有意义)

文件大小测试:

-s判断文件(非目录)为非空时为真

文件是否打开:

-N判断文件在上一次读取后被改过则为真。

-O判断文件owner为当前用户时为真

-G判断文件group是当前用户的主组时为真

文件测试:

使用方式为FILE1 -ef FILE2

-ef 判断两个文件是硬链接时为真

wKioL1mJemqTNkg_AACFCmmeLXY609.png

-nt判断前一个文件mtime新于后一个文件时为真

-ot判断前一个文件mtime旧于后一个文件时为真

4)组合测试条件

第一种方式:

COMMAND1 && COMMAND2 并且

COMMAND1 || COMMAND2 或者

! COMMAND

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

第二种方式:

EXPRESSION1 -a EXPRESSION2 并且

EXPRESSION1 -o EXPRESSION2 或者

! EXPRESSION

必须使用测试命令进行

wKiom1mJemuxrWaNAAB3RwYULVI975.png


9.接受输入

使用read来把输入值分配给一个或多个shell变量

-p 指定要显示提示

wKioL1mJemvTiAuLAABeYN1UDR4195.png

read -p “Enter a filename: “ FILE

wKioL1mJemzTlo5BAAB0u6NR4aQ596.png


-s静默输入,一般用于密码

wKiom1mJemyDL-wIAABNmHHXQZA142.png

(注意,必须是sp如果一起使用必须是-sp,不能用-ps

-n N 指定输入的字符长度N

wKiom1mJemzyUl7hAABRLEAUx2A986.png


-d ‘字符’ 输入结束符(就是当输入指定结束符时就算输入结束,会自动跳到下一行)

-t N TIMEOUTN (给用户的输入做限时规定。若超出-t参数后所规定的时间值后,脚本将终止用户的输入,可单独使用也可和其它参数配合连用。)

read 也可以从标准输入中读取值,给每个单词分配一个变量(注意:不支持管道)。如果变量数少于单词数,则所有剩余单词都被分配给最后一个变量

read 变量名1 [变量名2] < 文件

wKioL1mJem3wCNkFAABATKHUAlU129.png

也可以使用<<<直接导入具体值:

read 变量名1 [变量名2]<<< "1 [2] ..."

wKiom1mJem2B34lYAAAmvTkGn1w088.png


10.防止扩展

反斜线(\)会使随后的字符按原意解释

wKioL1mJem3j63m5AAAYm1tL1G4784.png

如图,此时我们只想使用$作为美元符号,因此需要加上\,如果不加则意思为引用变量5。但是我们没有定义变量5,所以为空。

也可以加引号来防止扩展

单引号()防止所有扩展

双引号()也防止所有扩展,但是以下情况例外:

$(美元符号) 变量扩展

`(反引号) 命令替换

\(反斜线) 禁止单个字符扩展

!(叹号) 历史命令替换

wKioL1mJem6iEXE4AAA2nZgwPiQ289.png


11. bash配置文件

按生效范围划分,存在两类:

全局配置:

/etc/profile

/etc/profile.d/*.sh

/etc/bashrc

个人配置:

~/.bash_profile

~/.bashrc


12.shell登录的两种方式

1)交互式登录

(1)直接通过终端输入账号密码登录

(2)使用“su - UserName”切换的用户

执行顺序:/etc/profile--> /etc/profile.d/*.sh ~/.bash_profile --> ~/.bashrc-->/etc/bashrc

bash已经定义好了,只要登录bash,就先加载/etc/profile文件

wKiom1mJfbywDFx1AABb9s7IPxQ627.png

通过/etc/profile中的代码调用/etc/profile.d/ 下所有的.sh文件

wKioL1mJfbzR7MIeAAAqo46HARs932.png

当读完所有.sh文件后,返回/etc/profile结束读取。然后bash会接着自动读取~/.bash_profile文件

wKiom1mJfb3y-YVdAABuPvRdBnk053.png

如图,~/.bash_profile文件中的命令调用~/.bashrc文件

wKioL1mJfb3x5dpzAACkfpf15aA762.png

~/.bashrc文件中的命令又调用/etc/bashrc文件

wKiom1mJfb7SBxIaAACv6YKzhE4353.png

其实在/etc/bashrc文件中也有命令调用/etc/profile.d/*.sh文件,但是由于之前已经调用过了,里面会判断就不再调用

总结:bash自身只会读/etc/profile ~/.bash_profile 其他都是在读取这两个文件调用读取出来的

2)非交互式登录

(1)su UserName

(2)图形界面下打开的终端

(3)执行脚本

(4)任何其它的bash实例

执行顺序:~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh

总结:非交互式登陆下,bash自身只读取~/.bashrc 文件,然后文件调用/etc/bashrc文件中又继续调用/etc/profile.d/*.sh

举个具体例子加深理解吧:

wKioL1mJfb6wXrVNAABZNs3sH2Q544.png

如图,我们分别在这5文件加上5段定义变量的话。此时查看5个变量的值,发现为空。因为此时并没有重新登录所以这些文件不重新读取。

wKioL1mJfb_SOfTaAAA8lSEH59s079.png

于是我们退出并重新登陆。

此时可以看到,分别有定义的值了。

wKiom1mJfb-S0_2QAAB4OfPebKo243.png

然后我们将C3改成C6

wKioL1mJfcCTm8fpAABX-5KXcvc142.png

(改完之后目前还是原来的结果,因为没有重新登录

然后我们使用非交互式登陆root

注意:非交互式登陆有一个特点,它不是登陆一个新的环境,会继承之前shell的所有变量,当然了,如果重新赋值了,它当然会被重新覆盖掉。

wKiom1mJfcCzkjyuAAA_cxLCqkI501.png

因此我们发现变量的值仍然不变。因为即使修改C,但是非登录shell并不读取~/.bash_profile文件,所以不会被重新赋值。

然后我们退出这个shell到之前的shell,将/etc/bashrc中的E5改为E7

wKioL1mJgMaBFeM4AABZ3SFHwbc300.png

因为从来都没有重新读取过,因此此时读取变量的话,仍然是123455个值。

然后再非交互式登陆到root下,

wKiom1mJgMbSp35yAABpaUPp_XE922.png

发现E的值改变了,因为非交互式登陆是需要读取/etc/bashrc文件的。

然后我们再退出到上一个shell,将B2改成B8

wKioL1mJgMexAsADAAB0Qv5-Qjw258.png

此时读取变量仍然是12345

wKiom1mJgMeAsTb_AAByhinZWjU923.png

然后使用非交互式登陆到liubei用户下,发现B的值也改变了。因为非交互式登陆也需要读取/etc/profile.d/*.sh文件的。

然后我们再退出,将D4改为D9

wKiom1mJgMfBw9MQAABtLi3RP-0271.png

发现变量仍然为

wKioL1mJgMiAf8NOAABFNqOarPc343.png

因为我们改的是root下的.bashrc文件,而liubei用户读取的应该是自己家目录的.bashrc文件,因此D的值不变。

然后我们退出并使用交互式登陆liubei用户

此时变量为:

wKiom1mJgMigilo1AABhB85oe-8451.png

因为交互式登录不会继承之前shell内容而是全部重新读取,而liubei用户又只会读自己家目录下的.bash_profile文件,而不会读取root下的.bash_profile文件,因此C的值为空。同理,也不会读D的值。因此这两个变量均为空。

PS修改文件后需生效有两种方法:

1重新启动shell进程(像刚才举例子中的方式)

2使用. source 例如: . ~/.bashrc


13. $-变量

hhashall,打开这个选项后,Shell 会将命令所在的路径hash下来,避免每次都要查询。通过set +hh选项关闭

iinteractive-comments,包含这个选项说明当前的shell 是一个交互式的 shell。所谓的交互式shell,在脚本中,i选项是关闭的。

mmonitor,打开监控模式,就可以通过Job control来控制进程的停止、继续,后台或者前台执行等。

Bbraceexpand,大括号扩展

HhistoryH选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如“!!”返回上最近的一个历史命令,“!n”返回第 n 个历史命令

wKioL1mJgMnSQ20qAAAbZtJcgT4954.png

正常查询时全部开启,某些变量可以通过命令开启或关闭

wKioL1mJgMmCo1mkAAC8rPbZ3U4160.png

如图,关闭h选项。

原文链接:https://www.f2er.com/bash/391551.html

猜你在找的Bash相关文章