shell编程实战
文章目录
- shell编程实战
- shell脚本
- shell脚本
- 脚本开头
- 脚本注释
- Shell 脚本的执行
- Shell 脚本开发的基本规范及习惯
- Shell变量
- 什么是shell变量
- 什么是变量
- Shell 变量的特性
- 变量类型
- 环境变量
- 设置环境变量
- 普通变量
- 普通变量定义
- 变量名及变量值要求
- 普通变量的定义及输出示例
- shell变量进阶
- Shell 中特殊变量
- Shell 位置参数变量
- Shell 进程中的特殊状态变量
- $?
- Shell 内置变量命令
- echo
- read
- 配置文件
- 验证:
- 扩展:
- 变量的数值计算
- 算术运算符
- (()) 双小括号数值运算命令
- (()) 双小括号数值运算的基础语法
- (()) 双小括号数运算实践
- let 命令
- bc 命令
- $[] 符号的运算
- Shell 脚本的条件测试
- Shell 脚本的条件测试
- 条件测试方法综述
- test 条件测试的简单语法及示例
- \[](中括号)条件测试语法及示例
- [[]](双中括号)条件测试语法及示例
- 文件判断表达式
- 文件判断表达式的用法
- 文件判断表达式举例
- 字符串判断表达式
- 字符串测试操作符
- 特殊条件判断表达式案例
- 字符串判断表达式
- 字符串测试操作符
- 整数二元比较操作符
- 整数二元比较操作符介绍
- 整数变量测试实践示例
- 逻辑操作符
- 逻辑操作符介绍
- 示例:
- 判断表达式 test、[]、[[]]、(())的区别总结
- if条件语句
- if 条件语句
- if 条件语句的语法
- 1. 单分支结构
- 2. 双分支结构
- 3. 多分支结构
- if 条件语句多种条件表达式语法
- 1. test条件表达式
- 2. []条件表达式
- 3. [[]]条件表达式
- 4. (())条件表达式
- 5. 命令表达式
- if语句实践
shell编程实战
创建第一个 Shell 脚本,shell变量基础知识,Shell 变量进阶知识,变量的数值计算实践,Shell 脚本的条件测试和if 条件语句的知识与实践。
shell脚本
shell脚本
在 Linux 系统中, Shell 脚本通常是在编辑器 vi/vim 中编写的,由UNIX/Linux命令、bash Shell 命令、程序结构控制语句和注释等内容组成。这里推荐用Linux自带的功能更强大的vim编辑器来编写,可以事先做一个别名alias vi=’vim’
,并使其永久生效,这样以后习惯输入 vi 的读者也就可以直接调用 vim
编辑器了。
脚本开头
一个规范的 Shell 脚本在第一行会指出由哪个程序(解释器)来执行脚本中的内容,这一行内容在Linux bash 的编程一般为:
[dyx@server bin 09:25:15]$ cat hello.sh
#!/bin/bash
其中,开头的"#!“字符又称为幻数(其实叫什么都无所谓,知道它的作用就好),在执行bash脚本的时候,内核会根据”#!"字符后的解释器来确定该用哪个程序解释这个脚本中的内容。
注意,这一行必须位于每个脚本顶端的第一行,如果不是第一行则为脚本注释行.
脚本注释
在 Shell 脚本中,跟在# 后面的内容表示注释,用来对脚本进行注释说明,注释部分不会被当作程序来执行,仅仅是给开发者和使用者看的,系统解释器是看不到的,更不会执行。
注释可自成一行,也可以跟在脚本命令的后面与命令在同一行。
开发脚本时,如果没有注释,那么团队里的其他人就会很难理解脚本对应内容的用途,而且若时间长了,自己也会忘记。因此,我们要尽量养成为所开发的 Shell 脚本书写关键注释的习惯,书写注释不光是为了方便别人,更是为了方便自己,避免影响团队的协作效率,以及给后来接手的人带来维护困难。
特别提示一下,注释尽量不要用中文,在脚本中最好也不要有中文。
Shell 脚本的执行
当 Shell 脚本运行时,它会先查找系统环境变量ENV,该变量指定了环境文件,再加载了上述环境变量文件后, Shell 就开始执行 Shell 脚本中的内容。
Shell 脚本是从上至下、从左至右依次执行每一行的命令及语句的,即执行完了一个命令后再执行下一个,如果在 Shell 脚本中遇到子脚本(即脚本嵌套)时,就会先执行子脚本的内容,完成后再返回父脚本继续执行父脚本内后续的命令及语句。通常情况下,在执行 Shell 脚本时,会向系统内核请求启动一个新的进程,以便在该进程中执行脚本的命令及子 Shell 脚本,基本流程如下。
准备:
[dyx@server ~ 09:21:30]$ mkdir bin
[dyx@server ~ 09:21:36]$ cd bin
[dyx@server bin 09:21:40]$ vim gather_os_info.sh
[dyx@server bin 09:24:38]$ cp gather_os_info.sh hello.sh
[dyx@server bin 09:24:51]$
[dyx@server bin 09:24:51]$ vim hello.sh
[dyx@server bin 09:25:15]$ cat hello.sh
#!/bin/bash
echo Hello World
[dyx@server bin 09:25:19]$ chmod +x hello.sh
Shell 脚本的执行通常可以采用以下几种方式:
-
/path/script-name 或 ./script-name:指在当前路径下执行脚本(脚本需要有执行权限),需要将脚本文件的权限先改为可执行,然后通过脚本绝对路径或相对路径就可以直接执行脚本了。
[dyx@server bin 09:26:40]$ ./hello.sh Hello World [dyx@server bin 09:26:50]$ /home/dyx/bin/hello.sh Hello World [dyx@server bin 09:27:06]$ pwd /home/dyx/bin
-
文件放 在$PATH下面
[dyx@server bin 09:28:01]$ cd /tmp [dyx@server tmp 09:28:09]$ hello.sh Hello World
-
bash script-name 或sh script-name:这是当脚本文件本身没有可执行权限(即文件权限属性x位为-号)时常使用的方法,或者脚本文件开头没有指定解释器时需要使用的方法。
[dyx@server bin 10:39:47]$ bash hello.sh Hello World
编辑示例:
[dyx@server bin 09:33:17]$ vim gather_os_info.sh
[dyx@server bin 09:49:55]$ cat gather_os_info.sh
#!/bin/bash#收集系统块设备信息
echo ====================系统块设备信息====================
lsblk
echo ====================系统块设备信息====================
echo#收集系统文件信息
echo ======================系统文件信息======================
df -h | grep -v tmps
echo ======================系统文件信息======================
echo#收集系统中cpu和内存使用情况 使用top命令echo ======================CPU Memory tasks 信息======================
top -n 1 |head -5
echo ======================CPU Memory tasks 信息======================
echo[dyx@server bin 09:41:29]$ top --help
top: inappropriate '-help'
Usage:top -hv | -bcHiOSs -d secs -n max -u|U user -p pid(s) -o field -w [cols]
[dyx@server bin 09:45:57]$ man top #验证
[dyx@server bin 09:39:27]$ bash gather_os_info.sh
====================系统块设备信息====================
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 100G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 99G 0 part ├─centos-root 253:0 0 50G 0 lvm /├─centos-swap 253:1 0 2G 0 lvm [SWAP]└─centos-home 253:2 0 47G 0 lvm /home
sr0 11:0 1 4.4G 0 rom
====================系统块设备信息==========================================系统文件信息======================
文件系统 容量 已用 可用 已用% 挂载点
devtmpfs 2.0G 0 2.0G 0% /dev
tmpfs 2.0G 0 2.0G 0% /dev/shm
tmpfs 2.0G 12M 2.0G 1% /run
tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup
/dev/mapper/centos-root 50G 2.0G 49G 4% /
/dev/mapper/centos-home 47G 33M 47G 1% /home
/dev/sda1 1014M 139M 876M 14% /boot
tmpfs 394M 0 394M 0% /run/user/1000
======================系统文件信息======================[dyx@server bin 09:49:05]$ bash gather_os_info.sh
====================系统块设备信息====================
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 100G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 99G 0 part ├─centos-root 253:0 0 50G 0 lvm /├─centos-swap 253:1 0 2G 0 lvm [SWAP]└─centos-home 253:2 0 47G 0 lvm /home
sr0 11:0 1 4.4G 0 rom
====================系统块设备信息==========================================系统文件信息======================
文件系统 容量 已用 可用 已用% 挂载点
devtmpfs 2.0G 0 2.0G 0% /dev
tmpfs 2.0G 0 2.0G 0% /dev/shm
tmpfs 2.0G 12M 2.0G 1% /run
tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup
/dev/mapper/centos-root 50G 2.0G 49G 4% /
/dev/mapper/centos-home 47G 33M 47G 1% /home
/dev/sda1 1014M 139M 876M 14% /boot
tmpfs 394M 0 394M 0% /run/user/1000
======================系统文件信息============================================CPU Memory tasks 信息======================
top - 09:49:09 up 50 min, 2 users, load average: 0.00, 0.01,
Tasks: 192 total, 1 running, 191 sleeping, 0 stopped, 0 z
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni, 96.8 id, 3.2 wa, 0.0 hi,
KiB Mem : 4026124 total, 3597868 free, 269748 used, 15850
KiB Swap: 2097148 total, 2097148 free, 0 used. 355052
======================CPU Memory tasks 信息======================
Shell 脚本开发的基本规范及习惯
Shell 脚本的开发规范及习惯非常重要,虽然这些规范不是必须要遵守的,但有了好的规范和习惯,可以大大提升开发效率,并能在后期降低对脚本的维护成本。
当多人协作开发时,大家有一个互相遵守的规范就显得更重要了。即使只是一个人开发,最好也采取一套固定的规范,这样脚本将会更易读、更易于后期维护,最重要的是要让自己养成一个一出手就很专业和规范的习惯。
下面来看看有哪些规范:
-
Shell 脚本的第一行是指定脚本解释。
#!/bin/bash
-
Shell 脚本的开头加版本、版权等信息。
#!/bin/bash # Date:16:29 2022-3-30 # Author:Created by laoma # Description:This script is used to... # Version:2.0
可修改
~/.vimrc
配置文件配置vim
编辑文件时自动加上以上信息的功能。 -
在 Shell 脚本中尽量不用中文(不限于注释)。
尽量用英文注释,防止本机或切换系统环境后中文乱码的困扰。如果非要加中文,请根据自身的客户端对系统进行字符集调整,如:
export LANG="zh_CN.UTF-8"
,并在脚本中,重新定义字符集设置,和系统保持一致。 -
Shell 脚本的命名应以.sh为扩展名。例如:
script-name.sh
。 -
Shell 脚本应存放在固定的路径下。
以下则是 Shell 脚本代码书写的良好习惯:
-
成对的符号应尽量一次性写出来,然后退格在符号里增加内容,以防止遗漏。
这些成对的符号包括:
{} [] '' `` ""
-
中括号([])两端至少要有1个空格,因此,键入中括号时即可留出空格[],然后再退格键入中间的内容,并确保两端都至少有一个空格,即先键入一对中括号,然后退1格,输入两个空格,再退1格,双中括号([[]])的写法也是如此。
-
对于流程控制语句,应一次性将格式写完,再添加内容。
-
通过缩进让代码更易读。
-
对于常规变量的字符串定义变量值应加引号,并且等号前后不能有空格,需要强引用的(指所见即所得的字符引用),则用单引号(’’),如果是命令的引用,则用反引号(‘’)。
-
脚本中的单引号、双引号及反引号必须为英文状态下的符号,其实所有的Linux字符及符号都应该是英文状态下的符号,这点需要特别注意。
Shell变量
什么是shell变量
什么是变量
简单地说,变量名是用一个固定的字符串(字符、数字和下划线的组合,不能以数字开头)代替更多、更复杂的内容,该内容里可能还会包含变量、路径、字符串等其他的内容。
变量是暂时存储数据的地方及数据标记,所存储的数据存在于内存空间中,通过正确地调用内存空间中变量的名字就可以取出与变量对应的数据。使用变量的最大好处就是使程序开发更为方便,当然,在编程中使用变量也是必须的,否则就很难完成相关的程序开发工作。
下面是定义变量和打印变量的示例:
[dyx@server ~ 10:36:56]$ username=zhangsan
变量的赋值方式为:先写变量名称,紧接着是这个字符,最后是值,中间无任何空格。
通过 echo
命令加上 $username
即可输出 username
变量的值。变量的内容一般要加双引号,以防止出错,特别是当值里的内容之间有空格时。
[dyx@server bin 11:31:21]$ echo $username
zhangsan
Shell 变量的特性
默认情况下,在bash Shell 中是不会区分变量类型的。例如:常见的变量类型为整数、字符串、小数等都当做字符串变量。这和其他强类型语言(例如:Java/C语言)是有区别的,当然,如果需要指定 Shell 变量的类型,也可以使用 declare
命令定义变量的类型,但在一般情况下没有这个需求。
变量类型
变量根据范围可分为两类:
-
全局变量,在创建它们的 Shell 及其派生出来的任意子进程 Shell 中使用。
-
局部变量,只能在创建它们的 Shell 函数或 Shell 脚本中使用。
变量根据是否是用户自定义也可分为两类:
- 普通变量:也称为常规变量,由开发者在开发脚本程序时创建。
- 环境变量:定义shell 执行环境。环境变量又可分为自定义环境变量和bash内置的环境变量。
环境变量
环境变量一般是指用export内置命令导出的变量,用于定义 Shell 的运行环境,保证 Shell 命令的正确执行。 Shell 通过环境变量来确定登录用户名、命令路径、终端类型、登录目录等,所有的环境变量都是系统全局变量,可用于所有子进程中,这包括编辑器、 Shell 脚本和各类应用。
环境变量可以在命令行中设置和创建,但用户退出命令行时这些变量值就会丢失,因此,如果希望永久保存环境变量,可在用户家目录下的 .bash_profile
或 .bashrc
(非用户登录模式特有,例如远程SSH)文件中,或者全局配置 /etc/bashrc
(非用户登录模式特有,例如远程SSH)或 /etc/profile
文件中定义。在将环境变量放入上述的文件中后,每次用户登录时这些变量都将被初始化。
按照系统规范,所有环境变量的名字均采用大写形式。在将环境变量应用于用户进程程序之前,都应该用 export
命令导出定义。有一些环境变量,比如HOME
、PATH
、USER
等,在用户登录之前就已经被/bin/login程序设置好了。通常环境变量被定义并保存在用户家目录下的 .bash_profile
文件或全局的配置文件 /etc/profile
中。
部分bash环境变量展示:
- EDITOR,默认编辑器。
- HISTFILE,历史文件位置。
- HISTSIZE,历史命令个数。
- PS1,命令行提示符。
- LANG,Shell 环境语言。
- PATH,命令搜素路径。
- HOME,当前用户家目录。
- USER,当前用户。
- PWD,当前 Shell 路径。
- IFS,字符串分隔符。
在查看设置的变量时,有3个命令可以显示变量的值:
- set 命令,输出所有的变量,包括全局变量和局部变量。
- env 命令,只显示全局变量,包括shell的环境。
- declare 命令,输出所有的变量、函数、整数和已经导出的变量。
set -o
命令显示bash Shell 的所有参数配置信息。
设置环境变量
如果想要设置环境变量,就要在给变量赋值之后或在设置变量时使用export
命令,具体设置见下文的示例。其实,除了 export
命令,带-x
选项的declare
内置命令也可以完成同样的功能(注意:此处不要在变量名前面加$)。
export
命令和 declare
命令的格式如下:
export 变量名=value
变量名=value ; export 变量名
declare -x 变量名=value
下面来看看让环境变量永久生效的常用设置文件。
-
用户的环境变量配置文件:
~/.bash_profile
和~/.bashrc
。推荐在(~/.bashrc)文件中设置。 -
全局环境变量的配置文件:
/etc/profile
、/etc/bashrc
、/etc/profile.d/
。**推荐在 /etc/bashrc 文件中设置。**若要在登录后初始化或显示加载内容,则把脚本文件放在/etc/profile.d/
下即可(无须加执行权限)。
普通变量
本地变量在用户当前 Shell 生存期的脚本中使用。例如,本地变量laoma
的定义为bingbing
, 这个值只在用户当前 Shell 生存期中有意义。如果在 Shell 中启动另一个进程或退出,那么变量laoma
的值将会无效。
普通变量定义
为普通变量的定义赋值,一般有以下3 种写法:
变量名=value
,赋值时不加引号。变量名='value'
,赋值时加单引号。变量名="value"
,赋值时加双引号。
变量名及变量值要求
- 变量名:一般是由字母、 数字 、下划线组成的,只可以以字母或下划线开头,例如:
laoma
、laoma_123
、laoma_training
。 - 变量值:可以用单引号或双引号引起来,也可不加引号,但是这三者的含义是不同的。
普通变量的定义及输出示例
#设置名字
[dyx@server ~ 10:37:07]$ first_name=zhang
[dyx@server ~ 10:37:15]$ last_name=san#输出结果的几种方式
[dyx@server ~ 10:37:24]$ echo $first_name $last_name
zhang san
[dyx@server ~ 10:37:28]$ echo "$first_name $last_name "
zhang san
[dyx@server ~ 10:37:32]$ echo $first_name-$last_name
zhang-san
[dyx@server ~ 10:37:45]$ echo $first_name_$last_name
san
[dyx@server ~ 10:37:50]$ echo ${first_name}_$last_name
zhang_san
shell变量进阶
Shell 中特殊变量
Shell 位置参数变量
在 Shell 中存在一些特殊且重要的变量,例如:$0
、$1
,我们称之为位置参数变量。要从命令行、函数或脚本执行等处传递参数时,就需要在 Shell 脚本中使用位置参数变量。
部分位置参数变量如下:
- $0,获取当前执行的 Shell 脚本的文件名,如果执行脚本包含了路径,那么就包括脚本路径。
- **n∗∗,获取当前执行的Shell脚本的∗∗第n个参数值∗∗。如果n大于9,则用大括号括起来,例如n**,获取当前执行的 Shell 脚本的**第n个参数值**。如果n大于9,则用大括号括起来,例如n∗∗,获取当前执行的Shell脚本的∗∗第n个参数值∗∗。如果n大于9,则用大括号括起来,例如{10},接的参数以空格隔开。
- $#,获取当前执行的 Shell 脚本后面接的参数数量。
- **∗∗∗,获取当前Shell脚本所有传参的参数,不加引号和‘***,获取当前 Shell 脚本所有传参的参数,不加引号和`∗∗∗,获取当前Shell脚本所有传参的参数,不加引号和‘@
相同;如果给
∗‘加上双引号,例如:‘"*`加上双引号,例如:`"∗‘加上双引号,例如:‘"*",则表示将所有的参数视为单个字符串,相当于
$1 $2 $3`。 - **@∗∗,获取当前Shell脚本所有传参的参数,不加引号和@**,获取当前 Shell 脚本所有传参的参数,不加引号和@∗∗,获取当前Shell脚本所有传参的参数,不加引号和*相同;如果给@加上双引号,例如:‘@加上双引号,例如:`@加上双引号,例如:‘@
,则表示将所有的参数视为不同的独立字符串,相当于
"$1"、“$2”、“$3”…`,这是将多参数传递给其他程序的最佳方式,因为它会保留所有的内嵌在每个参数里的任何空白。
示例1:showargs.sh 内容如下
[dyx@server bin 15:17:33]$ cat show_args.sh
#!/bin/bashecho $1
echo $2
echo $#
[dyx@server bin 11:21:27]$ ./show_args.sh arg{1..9} dyx
arg1
arg2
10
示例2:ssh_ctl 内容如下
[dyx@server bin 11:14:11]$ vim ssh_ctl
[dyx@server bin 11:15:46]$ chmod +x ssh_ctl
[dyx@server bin 11:18:00]$ cat ssh_ctl
#!/bin/bash
systemctl $1 sshd
执行效果如下:
[dyx@server bin 11:16:00]$ ssh_ctl status
● sshd.service - OpenSSH server daemonLoaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)Active: active (running) since 四 2025-10-09 08:58:21 CST; 2h 18min agoDocs: man:sshd(8)man:sshd_config(5)Main PID: 1055 (sshd)CGroup: /system.slice/sshd.service└─1055 /usr/sbin/sshd -D[dyx@server bin 11:17:19]$ ssh_ctl stop
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ===
Authentication is required to manage system services or units.
Authenticating as: root
Password:
==== AUTHENTICATION COMPLETE ===[dyx@server bin 11:17:27]$ ssh_ctl status
● sshd.service - OpenSSH server daemonLoaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)Active: inactive (dead) since 四 2025-10-09 11:17:27 CST; 2s agoDocs: man:sshd(8)man:sshd_config(5)Process: 1055 ExecStart=/usr/sbin/sshd -D $OPTIONS (code=exited, status=0/SUCCESS)Main PID: 1055 (code=exited, status=0/SUCCESS)[dyx@server bin 11:17:30]$ ssh_ctl start
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ===
Authentication is required to manage system services or units.
Authenticating as: root
Password:
==== AUTHENTICATION COMPLETE ===[dyx@server bin 11:17:56]$ ssh_ctl status
● sshd.service - OpenSSH server daemonLoaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)Active: active (running) since 四 2025-10-09 11:17:56 CST; 3s agoDocs: man:sshd(8)man:sshd_config(5)Main PID: 2082 (sshd)CGroup: /system.slice/sshd.service└─2082 /usr/sbin/sshd -D
拓展:
[dyx@server bin 11:19:01]$ cp ssh_ctl service_ctl
[dyx@server bin 11:19:48]$ vim service_ctl
[dyx@server bin 11:20:16]$ cat service_ctl
#!/bin/bash
systemctl $1 $2
[dyx@server bin 11:20:20]$ service status sshd
The service command supports only basic LSB actions (start, stop, restart, try-restart, reload, force-reload, status). For other actions, please try to use systemctl.
[dyx@server bin 11:20:52]$ ./service_ctl status sshd
● sshd.service - OpenSSH server daemonLoaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)Active: active (running) since 四 2025-10-09 11:17:56 CST; 3min 31s agoDocs: man:sshd(8)man:sshd_config(5)Main PID: 2082 (sshd)CGroup: /system.slice/sshd.service└─2082 /usr/sbin/sshd -D
Shell 进程中的特殊状态变量
$?
作用:获取执行上一个指令的执行状态返回值:0为成功,非零为失败,这个变量最常用。
[dyx@server bin 11:30:10]$ ls
gather_os_info.sh hello.sh service_ctl show_args.sh ssh_ctl
[dyx@server bin 11:30:24]$ echo $?
0
[dyx@server bin 11:30:29]$ ls andi
ls: 无法访问andi: 没有那个文件或目录
[dyx@server bin 11:30:35]$ echo $?
2
[dyx@server bin 11:30:37]$ grep selinux /etc/selinux/config
[dyx@server bin 11:31:00]$ echo $?
1
[dyx@server bin 11:31:03]$ grep -i selinux /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of three values:
SELINUXTYPE=targeted
[dyx@server bin 11:31:12]$ echo $?
0
[dyx@server bin 11:31:14]$ grep -i selinux /etc/
grep: /etc/: 是一个目录
[dyx@server bin 11:31:19]$ echo $?
2
Shell 内置变量命令
bash Shell 包含一些内置命令。 这些内置命令在目录列表里是看不见的,它们由 Shell 本身提供。常用的内部命令有: echo
、eval
、exec
、read
、shift
等。
echo
echo命令参数选项:
- -n,不换行输出内容。
- -e,解析转义字符(见下面的字符)
转义字符:
- \n,换行。
- \t,制表符(tab)。
- \b,退格。
[dyx@server ~ 16:07:13]$ echo -n "dyx";echo dyx
dyxdyx
[dyx@server ~ 16:39:49]$ echo -e "dyx\ndyx"
dyx
dyx
[dyx@server ~ 16:40:15]$ echo -e "123\b"
123
read
从标准输入读取字符串等信息, 传给 Shell 程序内部定义的变量。
配置文件
[root@server ~ 13:37:38]# vim useradd.sh
[root@server ~ 14:29:51]# cat useradd.sh
#!/bin/bash
#提供用户名
read -p "请输入用户名" user_name #提供用户性别
read -p "请输入用户性别:" user_sex #提供用户年龄
read -p "请输入用户年龄:" user_age #提供用户密码
read -sp "请输入用户密码:" user_pass
echo#添加用户
useradd ${user_name}
#提供用户密码
echo ${user_pass} | passwd --stdin ${user_name} #将以上用户信息存储到/etc/users.info
echo ${user_name}:${user_sex}:${user_age}:x >> /etc/users.info#打印用户信息存储到/etc/users.info
echo "用户信息已经存储到/etc/users.info"
验证:
[root@server ~ 13:59:28]# bash useradd.sh
请输入用户名zhangsan
请输入用户性别:male
请输入用户年龄:2
请输入用户密码:
useradd:用户“zhangsan”已存在
更改用户 zhangsan 的密码 。
passwd:所有的身份验证令牌已经成功更新。
用户信息已经存储到/etc/users.info
扩展:
给出指定文件内容,从中创建用户
[root@server ~ 14:09:37]# userdel -r zhangsan[root@server ~ 14:10:20]# cp /etc/users.info users.info
[root@server ~ 14:10:48]# vim users.info
[root@server ~ 14:11:54]# cat users.info
user_name=zhangsan
user_sex=male
user_age=2
user_pass=123[root@server ~ 14:12:27]# source users.info
[root@server ~ 14:12:40]# echo $user_name
zhangsan
[root@server ~ 14:12:51]# cp useradd.sh useradd-2.sh
[root@server ~ 14:15:48]# vim useradd-2.sh
[root@server ~ 14:29:47]# cat useradd-2.sh
#!/bin/bash
source /root/users.info
#添加用户
useradd ${user_name}#提供用户密码
echo ${user_pass} | passwd --stdin ${user_name}[root@server ~ 14:20:03]# bash useradd-2.sh
更改用户 zhangsan 的密码 。
passwd:所有的身份验证令牌已经成功更新。
变量的数值计算
算术运算符
如果要执行算术运算,就会离不开各种运算符号,和其他编程语言类似,Shell 也有很多算术运算符。
下面就给大家介绍一下常见的 Shell 算术运算符:
- +、-,一元正号和负号。
- +、-,加法和减法。
- *、/、%,乘法、除法、取余(取模)。
- **,幂运算。
- ++、–,增加及减少,可前置也可放在变量结尾。
- !、&&、||,逻辑非(取反)、逻辑与(and)、逻辑或(or)。
- <、<=、>、>=,比较符号(小于、小于等于、大于、大于等于)。
- ==、!=、=,比较符号(相等、不相等,对于字符串也可以表示相当于)。
- <<、>>,向左移位、向右移位。
- ~、|、&、^,按位取反、按位异或、按位与、按位。
- =、+=、-=、*=、/=、%=,赋值运算符,例如
a+=1
相当于a=a+1
,a-=1
相当于a=a-1
。
Shell 中常见的算术运算命令:
- (()),用于整数运算的常用运算符,效率很高。
- let,用于整数运算,类似于
(())
。 - expr,可用于整数运算,但还有很多其他的额外功能。
- bc,Linux下的一个计算器程序(适合整数及小数运算)。
- $[],用于整数运算。
- awk,awk 既可以用于整数运算,也可以用于小数运算。
- declare,定义变量值和属性,-i参数可以用于定义整形变量,做运算。
(()) 双小括号数值运算命令
双小括号 (()) 的作用是进行数值运算与数值比较,它的效率很高,用法灵活,是企业场景运维人员经常采用的运算操作符。
(()) 双小括号数值运算的基础语法
双小括号 (()) 的操作方法:
-
((i=i+1)),此种书写方法为运算后赋值法,即将i+1的运算结果赋值给变量i。
注意:不能用
echo ((i=i+l))
输出表达式的值,可以用echo $((i=i+l))
输出其值。 -
**i=((i+1))∗∗,可以在‘(())‘前加‘((i+1))**,可以在 `(())` 前加 `((i+1))∗∗,可以在‘(())‘前加‘` 符,表示将表达式运算后赋值给i。
-
(( 8>7 && 5==5)),可以进行比较操作,还可以加入逻辑与和逻辑或,用于条件判断。
-
**echo ((2+1))∗∗,需要直接输出运算表达式的运算结果时,可以在‘(())‘前加‘((2+1))**,需要直接输出运算表达式的运算结果时,可以在 `(())` 前加 `((2+1))∗∗,需要直接输出运算表达式的运算结果时,可以在‘(())‘前加‘` 符。
(()) 双小括号数运算实践
[dyx@server bin 14:39:31]$ echo $(($(echo {1..100}| sed 's/ /+/g') ))
5050
[dyx@server bin 14:39:48]$ ((1+2))
[dyx@server bin 14:39:56]$ echo $?
0
[dyx@server bin 14:40:05]$ echo $((1+2))
3[dyx@server bin 14:39:16]$ echo $[$(echo {1..100}| sed 's/ /+/g')]
5050
变量前后使用–和++特殊运算符的表达式
[dyx@server ~ 16:52:08]$ a=10
[dyx@server ~ 16:53:22]$ echo $((a++))
10
[dyx@server ~ 16:53:31]$ echo $a
11
[dyx@server ~ 16:53:38]$ echo $((--a))
10
[dyx@server ~ 16:54:09]$ echo $a
10
[dyx@server ~ 16:54:11]$ echo $((a--))
10
[dyx@server ~ 16:54:16]$ echo $a
9
总结:
- 执行
echo $((a++))
和echo $((a--))
命令输出整个表达式时,输出的值即为a
的值,表达式执行完毕后,会对a
进行++
、--
的运算 - 执行
echo $((++a))
和echo $((--a))
命令输出整个表达式时,会先对a
进行++
、--
的运算,然后再输出表达式的值,即为a运算后的值
let 命令
let运算命令的语法格式为:let 表达式
let表达式的功能等同于:((表达式))
[dyx@server bin 14:40:17]$ let 1+2
[dyx@server bin 14:40:23]$ let sum=1+2
[dyx@server bin 14:40:27]$ echo $sum
3
bc 命令
bc
是UNIX/Linux下的计算器,因此,除了可以作为计算器来使用,还可以作为命令行计算工具使用。
[dyx@server bin 14:40:33]$ bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
1.1+2.2
3.3
q
0
quit
[dyx@server bin 14:41:01]$ echo 1.1+2.2 |bc
3.3
$[] 符号的运算
[dyx@server bin 11:50:17]$ echo $[1+2]
3[dyx@server ~ 16:40:33]$ count=3
[dyx@server ~ 16:51:52]$ echo $[(count+1)*3]
12
Shell 脚本的条件测试
Shell 脚本的条件测试
条件测试方法综述
通常,在 bash 的各种条件结构和流程控制结构中都要进行各种测试,然后根据测试结果执行不同的操作,有时也会与if等条件语句相结合,来完成测试判断,以减少程序运行的错误。
执行条件判断表达式后通常会返回"真"或"假",就像执行命令后的返回值为0,表示真;非0,表示假。
在 bash 编程里,条件测试常用的语法如下:
- 语法1:test <判断表达式>,test命令和"<判断表达式>"之间至少有一个空格。
- 语法2:[ <判断表达式> ],和test命令的用法相同,这是推荐方法。
[]
的边界和内容之间至少有一个空格。 - 语法3:[[ <判断表达式> ]],是比test和[]更新的语法格式。
[[]]
的边界和内容之间至少有一个空格。 - 语法4:(( <判断表达式> )),一般用于 if 语句。
(())
(双小括号)两端不需要有空格。 - 语法5:comand,命令的返回值确定表达式的真值或假值。
有几个注意事项需要说明一下:
- 语法1中的
test命令
和语法2中的[]
是等价的,语法3
中的[[]]
为扩展的test命令,语法4中的(())
常用于计算。建议使用相对友好的语法2,即中括号[]
的语法格式。 - 在
[[ ]]
(双中括号)中可以使用通配符等进行模式匹配,这是其区别于其他几种语法格式的地方。 &&、||、>、<
等操作符可以应用于[[]]
中,但不能应用于[]
中,在[]
中一般用-a、-o、-gt(
用于整数)、-lt
(用于整数)代替上述操作符。- 对于整数的关系运算,也可以使用 Shell 的算术运算符
(())
。
test 条件测试的简单语法及示例
test条件测试的语法格式为: test <判断表达式>
[dyx@server ~ 15:49:44]$ help test
test: test [表达式]Evaluate conditional expression.Exits with a status of 0 (true) or 1 (false) depending onthe evaluation of EXPR. Expressions may be unary or binary. Unaryexpressions are often used to examine the status of a file. Thereare string operators and numeric comparison operators as well.The behavior of test depends on the number of arguments. Read thebash manual page for the complete specification.File operators:-a FILE True if file exists.-b FILE True if file is block special.-c FILE True if file is character special.-d FILE True if file is a directory.-e FILE True if file exists.-f FILE True if file exists and is a regular file.-g FILE True if file is set-group-id.-h FILE True if file is a symbolic link.-L FILE True if file is a symbolic link.-k FILE True if file has its `sticky' bit set.-p FILE True if file is a named pipe.-r FILE True if file is readable by you.-s FILE True if file exists and is not empty.-S FILE True if file is a socket.-t FD True if FD is opened on a terminal.-u FILE True if the file is set-user-id.-w FILE True if the file is writable by you.-x FILE True if the file is executable by you.-O FILE True if the file is effectively owned by you.-G FILE True if the file is effectively owned by your group.-N FILE True if the file has been modified since it was last read.FILE1 -nt FILE2 True if file1 is newer than file2 (according tomodification date).FILE1 -ot FILE2 True if file1 is older than file2.FILE1 -ef FILE2 True if file1 is a hard link to file2.String operators:-z STRING True if string is empty.-n STRINGSTRING True if string is not empty.STRING1 = STRING2True if the strings are equal.STRING1 != STRING2True if the strings are not equal.STRING1 < STRING2True if STRING1 sorts before STRING2 lexicographically.STRING1 > STRING2True if STRING1 sorts after STRING2 lexicographically.Other operators:-o OPTION True if the shell option OPTION is enabled.-v VAR True if the shell variable VAR is set! EXPR True if expr is false.EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.EXPR1 -o EXPR2 True if either expr1 OR expr2 is true.arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne,-lt, -le, -gt, or -ge.Arithmetic binary operators return true if ARG1 is equal, not-equal,less-than, less-than-or-equal, greater-than, or greater-than-or-equalthan ARG2.Exit Status:Returns success if EXPR evaluates to true; fails if EXPR evaluates tofalse or an invalid argument is given.
示例1:判断文件是否存在
[dyx@server ~ 15:49:57]$ test -f file && echo true
[dyx@server ~ 15:50:28]$ test -f file && echo true || echo false
false#文件类型
[dyx@server ~ 15:53:17]$ test -d /etc && echo /etc is dictory.
/etc is dictory.
该语句表示如果file文件存在,则输出true,否则输出false。这里的&&
是逻辑与,||
是逻辑或。test的-f
参数用于测试文件是否为普通文件,test命令若执行成功(为真),则执行&&后面的命令,而||
后面的命令是test命令执行失败之后(为假)所执行的命令。
示例2:
# 如果目录不存在,就创建目录
[dyx@server bin 14:41:14]$ test ! -d /tmp/zhangsan && mkdir /tmp/zhangsan
[dyx@server bin 15:02:56]$ echo $?
0# 第二次执行,目录已经存储
[dyx@server bin 15:03:06]$ test ! -d /tmp/zhangsan && mkdir /tmp/zhangsan
[dyx@server bin 15:03:09]$ echo $?
1# 如果目录存在,就提示目录存在
[dyx@server bin 15:04:21]$ test -d /tmp/zhangsan && echo /tmp/zhangsan is exist.
/tmp/zhangsan is exist.
示例3:
[dyx@server bin 15:16:54]$ vim ssh_ctl
[dyx@server bin 15:17:41]$ cat ssh_ctl
#!/bin/bash
test "$USER" != "root" && echo Please run as root. && exit
systemctl $1 sshd#普通用户执行
[dyx@server bin 15:17:39]$ bash ssh_ctl status
Please run as root.#root用户执行
[root@server ~ 15:18:01]# cd /home/dyx/bin
[root@server bin 15:20:05]# bash ssh_ctl status
● sshd.service - OpenSSH server daemonLoaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)Active: active (running) since 四 2025-10-09 11:17:56 CST; 4h 2min agoDocs: man:sshd(8)man:sshd_config(5)Main PID: 2082 (sshd)CGroup: /system.slice/sshd.service└─2082 /usr/sbin/sshd -D10月 09 11:17:56 server systemd[1]: Starting OpenSSH server ...
10月 09 11:17:56 server sshd[2082]: Server listening on 0.0....
10月 09 11:17:56 server sshd[2082]: Server listening on :: p...
10月 09 11:17:56 server systemd[1]: Started OpenSSH server d...
10月 09 13:37:38 server sshd[2288]: Accepted password for ro...
10月 09 13:57:19 server sshd[2318]: Accepted password for ro...
10月 09 15:18:19 server sshd[2588]: Accepted password for dy...
Hint: Some lines were ellipsized, use -l to show in full.
[](中括号)条件测试语法及示例
[]
条件测试的语法格式为:[ < 判断表达式> ]
注意:中括号内部的两端要有空格,[]
和test等价,即test的所有判断选项都可以直接在[]
里使用。
**示例1:**判断文件是否存在
[dyx@server ~ 15:51:11]$ [ -f false ] && echo true || echo false
false
该语句表示如果file文件存在,则输出true,否则输出false。这里的&&
是逻辑与,||
是逻辑或。test的-f参数用于测试文件是否为普通文件,test命令若执行成功(为真),则执行&&
后面的命令,而||
后面的命令是test命令执行失败之后(为假)所执行的命令。
[[]](双中括号)条件测试语法及示例
[[]]
条件测试的语法格式为: [[ < 判断表达式> ]]
。
注意:双中括号里的两端也要有空格。
**示例1:**判断文件是否存在
[dyx@server ~ 15:52:49]$ [[ -f false ]] && echo true || echo false
false
该语句表示如果file文件存在,则输出true,否则输出false。这里的&&是逻辑与,||是逻辑或。test的-f参数用于测试文件是否为普通文件,test命令若执行成功(为真),则执行&&后面的命令,而||后面的命令是test命令执行失败之后(为假)所执行的命令。
文件判断表达式
文件判断表达式的用法
文件测试常用选项:
- -d 文件,d的全拼为directory文件存在且为目录则为真,即判断表达式成立。
- -f 文件,f的全拼为file文件存在且为普通文件则为真,即判断表达式成立。
- -e 文件,e的全拼为exist文件存在则为真,即判断表达式成立。区别于"-f",-e不辨别是目录还是文件。
- -r 文件,r的全拼为read文件存在且可读则为真,即判断表达式成立。
- -s 文件,s的全拼为size文件存在且文件size不为0则为真,即判断表达式成立。
- -w 文件,w的全拼为write文件存在且可写则为真,即判断表达式成立。
- -x 文件,x的全拼为executable文件存在且可执行则为真,即判断表达式成立。
- -L 文件,L的全拼为link文件存在且为链接文件则为真,即判断表达式成立。
- f1 -nt f2,nt的全拼为newer than,文件fl比文件f2新则为真,即判断表达式成立。根据文件的修改时间来计算。
- f1 -ot f2,ot的全拼为older than,文件fl比文件f2旧则为真,即判断表达式成立。根据文件的修改时间来计算。
文件判断表达式举例
[dyx@server ~ 15:53:17]$ test -d /etc && echo /etc is dictory.
/etc is dictory.[dyx@server ~ 15:54:05]$ [ -d /etc ]&& echo /etc is dictory.
/etc is dictory.[dyx@server ~ 15:54:49]$ [ -r /etc/shadow ]&& cat /etc/shadow || echo hello
hello
字符串判断表达式
字符串测试操作符
字符串测试操作符的作用包括:比较两个字符串是否相同、测试字符串的长度是否为零、字符串是否为NULL等。
常用字符串测试操作符:
- -n “字符串”,若字符串的长度不为0,则为真,即判断表达式成立,n可以理解为no zero。
- -z “字符串”,若字符串的长度为0,则为真,即判断表达式成立,z可以理解为zero的缩写。
- “串1” = “串2”,若字符串1等于字符串2,则为真,即判断表达式成立,可使用"==“代替”="。
- “串1” != “串2”,若字符串1不等于字符串2,则为真,即判断表达式成立,但不能用"!==“代替”!="。
以下是针对字符串测试操作符的提示:
- 对于字符串的测试,一定要将字符串加双引号之后再进行比较,如
[ -n "$myvar" ]
,特别是使用[]
的场景。 - 比较符号(例如=和!=)的两端一定要有空格。
[dyx@server bin 15:22:56]$ data_path=/tmp/dyx
[dyx@server bin 17:05:27]$ mkdir ${data_path}
[dyx@server bin 17:05:34]$ [ -d ${data_path} ] && echo ${data_path} is exist
/tmp/dyx is exist[dyx@server bin 17:05:41]$ rmdir ${data_path}
[dyx@server bin 17:05:48]$ [ -d ${data_path} ] || echo ${data_path} is not exist
/tmp/dyx is not exist[dyx@server bin 17:05:55]$ [ -r /etc/shadow ] && cat /etc/shadow || echo hello
hello
特殊条件判断表达式案例
以下写法适用于所有的条件判断表达式,是工作中比较常用的替代if语句的方法。判断条件判断表达式的条件成立或不成立后,还需要继续执行多条命令语句的语法。
# 格式1
[ 条件1 ] && {
命令1
命令2
命令3
}# 格式2
[[ 条件1 ]] && {
命令1
命令2
命令3
}# 格式3
test 条件1 && {
命令1
命令2
命令3
}
示例:
[dyx@server bin 17:06:01]$ [ -w ~/.bashrc ] && {
> echo "alias sa='ssh root@servera'" >> ~/.bashrc
> echo "alias sb='ssh root@serverb'" >> ~/.bashrc
> echo "alias sc='ssh root@serverc'" >> ~/.bashrc
> }[dyx@server bin 17:08:03]$ tail -3 ~/.bashrc
alias sa='ssh root@servera'
alias sb='ssh root@serverb'
alias sc='ssh root@serverc'
字符串判断表达式
字符串测试操作符
字符串测试操作符的作用包括:比较两个字符串是否相同、测试字符串的长度是否为零、字符串是否为NULL等。
常用字符串测试操作符:
- -n “字符串”,若字符串的长度不为0,则为真,即判断表达式成立,n可以理解为no zero。
- -z “字符串”,若字符串的长度为0,则为真,即判断表达式成立,z可以理解为zero的缩写。
- “串1” = “串2”,若字符串1等于字符串2,则为真,即判断表达式成立,可使用"==“代替”="。
- “串1” != “串2”,若字符串1不等于字符串2,则为真,即判断表达式成立,但不能用"!==“代替”!="。
以下是针对字符串测试操作符的提示:
- 对于字符串的测试,一定要将字符串加双引号之后再进行比较,如
[ -n "$myvar" ]
,特别是使用[]
的场景。 - 比较符号(例如=和!=)的两端一定要有空格。
整数二元比较操作符
整数二元比较操作符介绍
整数二元比较操作符使用说明如下:
[]和test中比较符号 | (())和[[]]中比较符号 | 说明 |
---|---|---|
-eq | ==或= | 相等,全拼为 equal |
-ne | != | 不相等,全拼为 not equal |
-gt | > | 大于,全拼为 greater than |
-ge | >= | 大于等于,全拼为 greater equal |
-It | < | 小于,全拼为less than |
-le | <= | 小于等于,全拼为 less equal |
以下是针对上述符号的特别说明:
=
和!=
也可在[]中做比较使用,但在[]中使用包含>
和<
的符号时,需要用反斜线转义,有时不转义虽然语法不会报错,但是结果可能会不对。- 也可以在[[]]中使用包含
-gt
和-lt
的符号,但是不建议这样使用。 - 比较符号两端也要有空格。
[dyx@server ~ 16:01:30]$ [ 2 -gt 3 ]&& echo true ||echo flase
flase
[]、[[]]、(())用法的小结:
- 整数加双引号的比较是对的。
[[]]
中用类似-eq等的写法是对的,[[]]中用类似>、<的写法也可能不对,有可能会只比较第一位,逻辑结果不对。[]
中用类似>、<的写法在语法上虽然可能没错,但逻辑结果不对,可以使用=、!=正确比较。(())
中不能使用类似-eq等的写法,可以使用类似>、<的写法。
整数变量测试实践示例
[dyx@server ~ 16:02:31]$ a=98
[dyx@server ~ 16:02:53]$ b=99
[dyx@server ~ 16:02:56]$ [ $a -eq $b ]&& echo true || echo fales
fales
[dyx@server ~ 16:03:19]$ [ $a -ne $b ]&& echo true || echo fales
true
[dyx@server ~ 16:03:30]$ [ $a = $b ]&& echo true || echo fales
fales
逻辑操作符
逻辑操作符介绍
表达式中逻辑操作符使用说明如下:
[]和test中逻辑操作符 | [[]]和(())中逻辑操作符 | 说明 |
---|---|---|
-a | && | and,与,两端都为真,则结果为真 |
-o | II | or,或 ,两端有一个为真,则结果为真 |
! | ! | not,非,两端相反,则结果为真 |
对于上述操作符,有如下提示:
- 逻辑操作符前后的表达式是否成立,一般用真假来表示。
- "!"的中文意思是反,即与一个逻辑值相反的逻辑值。
- -a的中文意思是“与”(and或&&),前后两个逻辑值都为“真”,综合返回值才为“真”,反之为“假”。
- -o的中文意思是“或”(or或||),前后两个逻辑值只要有一个为“真”,返回值就为“真”。
表达式外:&&或||可用于连接两个含[]、test或[[]]的表达式:
-
使用&&表达式时:
-
当左边为真,右边表达式才会执行。
-
当左边为假,右边表达式不会执行。
-
-
使用||的表达式时:
-
当左边为真,右边表达式不会执行。
-
当左边为假,右边表达式才会执行。
-
示例:
[dyx@server ~ 16:05:30]$ file=/etc/passwd
[dyx@server ~ 16:05:37]$ [ -f $file -a -r $file ]&& head -1 $file
root:x:0:0:root:/root:/bin/bash[dyx@server ~ 16:05:39]$ num=10
[dyx@server ~ 16:06:17]$ [ $num -lt 20 -o $num -gt 1 ] && echo $num is between 1 and 20.
10 is between 1 and 20.[dyx@server ~ 16:06:36]$ [ $num -gt 3 -a $num -lt 10 ]&& echo "3<$num<10"||echo "$num is not between 3 and 10"
10 is not between 3 and 10[dyx@server ~ 16:07:04]$ num=5
[dyx@server ~ 16:07:11]$ [ $num -gt 3 -a $num -lt 10 ]&& echo "3<$num<10"||echo "$num is not between 3 and 10"
3<5<10
判断表达式 test、[]、[[]]、(())的区别总结
判断表达式符号 | [] | test | [[]] | (()) |
---|---|---|---|---|
边界是否需要空格 | 需要 | 需要 | 需要 | 不需要 |
逻辑操作符 | !、-a、-o | !、 -a、 -o | !、&&、|| | !、&&、|| |
整数比较操作符 | -eq、-ne、-gt、-ge、-lt、-le | -eq、-ne、-gt、-ge、-lt、-le | -eq、-ne、-gt、-ge、-lt、-le | =、!=、>、>=、<、<= |
字符串比较操作符 | =、== 、!= | =、== 、!= | =、== 、!= | == 、!= |
是否支持通配符匹配 | 不支持 | 不支持 | 支持(=~) | 不支持 |
if条件语句
if 条件语句
if条件语句是Linux运维人员在实际生产工作中使用得最频繁也是最重要的语句,因此,请务必重视if条件语句的知识,并牢固掌握。
if 条件语句的语法
if条件语句,其语义类似于汉语里的“如果…那么”。
1. 单分支结构
第一种语法:
if <条件表达式>then 指令
fi
第二种语法:
if <条件表达式>;then指令
fi
上文的“<条件表达式>”部分可以是test、口、[[]]、(())等条件表达式,甚至可以直接使用命令作为条件表达式。每个if条件语句都以if开头,并带有then,最后以fi结尾。
第二种语法中的分号相当于命令换行,上面的两种语法含义是相同的,读者可根据习惯自行选择。
本书主要使用第二种语法格式。
在所有编程语言里,if条件语句几乎是最简单的语句格式,且用途最广。当if后面的<条件
表达式>成立时(真),就会执行then后面的指令或语句;否则,就会忽略then后面的指令或语句,
转而执行fi下面的程序。
if单分支语句执行流程逻辑图如下:
条件语句还可以嵌套(即if条件语句里面还有if条件语句),注意每个if条件语句中都要有一个与之对应的fi(if反过来写),每个if和它下面最近的fi成对搭配,语法示例如下:
if <条件表达式>;thenif <条件表达式>;then指令fi
fi
提示:通常在书写Shell条件语句时,要让成对的条件语句关键字的缩进相对应,以便于阅读浏览。
前文曾讲解过的文件条件表达式:
[ ! -d /tmp/dyx ] && mkdir /tmp/dyx
等价于下面的if条件语句:
if [ ! -d /tmp/dyx ];thenmkdir /tmp/dyx
fi
记忆小技巧:女孩对男孩说。
如果 你有房;那么 我就嫁给你 果如
2. 双分支结构
if条件语句的双分支结构主体则为:“如果…,那么…,否则…”。
if条件语句的双分支结构语法为:
if <条件表达式>;then指令集1
else指令集2
fi
if 双分支语句执行流程逻辑图如下:
前文的文件测试条件表达式
[ -d /tmp/dyx ] && echo /tmp/dyx is exist || mkdir /tmp/dyx
就相当于下面的双分支的if条件语句:
if [ -d /tmp/dyx ];thenecho /tmp/dyx is exist
elsemkdir /tmp/dyx
fi
记忆小技巧:女孩对男孩说。
如果 你有房;那么 我就嫁给你 否则 我再考虑考虑 果如
3. 多分支结构
if条件语句多分支结构的主体为:“如果…,那么…,否则如果…,那么,否则如果…,那么…,否则…”。
if条件语句多分支语法为:
if <条件表达式1>;then指令1
elif <条件表达式2>;then指令2
else指令3
fi
多个elif
if <条件表达式1>;then指令
elif <条件表达式2>;then指令
elif <条件表达式3>;then指令
else指令
fi
提示:
- 注意多分支elif的写法,每个elif都要带有then。
- 最后结尾的else后面没有then。
if多分支语句执行流程对应的逻辑图如下:
记忆小技巧:女孩对男孩说。
如果 你有房;那么 我就嫁给你 或者 你有钱;那么 我也可以嫁给你 否则 我再考虑考虑 果如
if 条件语句多种条件表达式语法
if条件语句(包括双多分支if)的“<条件表达式>”部分可以是test、[]、[[]]、(())等条件表达式,甚至还可以直接使用命令作为条件表达式,具体的语法如下。
1. test条件表达式
if test 表达式;then指令
fi
2. []条件表达式
if [ 字符串 或 算术表达式 ];then指令
fi
3. [[]]条件表达式
if [[ 字符串 或 算术表达式 ]];then指令
fi
4. (())条件表达式
if ((算术表达式));then指令
fi
5. 命令表达式
if 命令;then指令
fi
说明:以上表达式除了语法不同之外,具体的应用是一致的,实际工作场景中,读者只需选择一种适合自己习惯的表达式就好。
if语句实践
示例1:检测sshd服务是否运行,如果未运行则启动sshd服务。
[root@server ~ 17:24:48]# vim test_ssh.sh
[root@server ~ 17:25:56]# systemctl stop sshd
[root@server ~ 17:26:14]# bash test_ssh.sh
sshd is not running
[root@server ~ 17:26:16]# cat test_ssh.sh
#!/bin/bash
systemctl is-active sshd &>/dev/null
if [ $? -ne 0 ];thenecho "sshd is not running"systemctl start sshd
fi
示例2:检测sshd服务是否运行,如果未运行则启动sshd服务;如果运行,输出 “Running”。
[root@server ~ 17:26:29]# vim test_ssh.sh
[root@server ~ 17:29:50]# cat test_ssh.sh
#!/bin/bash
systemctl is-active sshd &>/dev/null
if [ $? -ne 0 ];thenecho "sshd is not running"echo "Starting sshd... ..."systemctl start sshd
else echo "sshd is running"
fi[root@server ~ 17:29:43]# bash test_ssh.sh
sshd is running