万字长文带你入门shell编程(超详细)
一、概述
Shell 是计算机操作系统中用户与操作系统内核之间的接口层,它提供了一种方式让用户能够通过命令行界面(CLI)与操作系统交互。Shell 可以被视为一个命令解释器,它接收用户输入的命令,解析这些命令,并将它们传递给操作系统以便执行。Shell 也会显示命令的执行结果,以及提供一系列的脚本语言功能,如变量、循环、条件判断和函数,使得用户能够编写脚本来自动化任务。
Shell脚本运行过程:
常见的 Shell 命令解释器:
-
Bourne Shell (
sh
):UNIX 系统中最古老的 shell,是许多其他 shell 的基础。 -
C Shell (
csh
):由贝尔实验室开发,提供了更类似于 C 语言的语法结构。 -
Korn Shell (
ksh
):结合了 Bourne Shell 和 C Shell 的特性,提供了更多的功能和改进。 -
Bash Shell (
bash
):GNU 项目的一部分,是 Linux 和 macOS 中最常用的 shell,提供了丰富的功能和广泛的脚本支持。 -
Z Shell (
zsh
):一个高度可配置的 shell,提供了许多高级功能,如自动补全和语法高亮。 -
PowerShell:Microsoft 开发的 shell 和脚本语言,主要用于 Windows 系统,也支持 Linux 和 macOS。
查看自己linux系统的默认解析:echo $SHELL
二、Shell脚本编写规范
首行设置Shell解释器类型,语法如下:#!/bin/bash单行注释:#注释内容多行注释::<<!#注释内容1#注释内容2!
Shell脚本编写Hello World案例
helloworld.sh文件内容(注意文件以.sh结尾)
脚本文件执行
注意:
当我执行 ./helloworld.sh的时候,报错了,第一次报错是因为权限不足,这时候修改一下文件权限就行;第二次报错/bin/bash/: bad interpreter: Not a directory
。这个错误表明脚本的第一行(称为 shebang 行)指向的解释器路径有问题。在文件的开头我编写的是#!/bin/bash/,这里编写错了,正确的应该是#!/bin/bash
三、环境变量
有Linux基础的同学都知道当我们在shell终端执行cd命令的时候,实际上执行的就是/usr/bin/cd这个程序文件,那么我们是否会有这样的疑问,为何我们无论在哪个目录下都能执行cd命令?这其实就是环境变量的作用;我们可以执行env来查看当前的系统环境变量:
Linux知识回顾:
如果想输出特定的环境变量,可以执行echo $环境变量名:
设置临时环境变量export 变量名=变量值:
永久生效:
定义与使用
1.局部变量
在一个shell脚本文件中定义的变量只能给当前的脚本文件使用,这个变量就叫局部变量
定义语法:
var_name=name
语法规则:
1.变量名称可以有字母,数字和下划线组成,但是不能以数字开头
2.等号两侧不能有空格
3.在bash环境中,变量的默认类型都是字符串类型,无法直接进行数值运算4.变量的值如果有空格,必须使用双引号括起来
5.不能使用shell的关键字作为变量名称
下面展示变量的定义与访问:
2.常量
定义之后就不能修改
语法readonly 变量名
3.全局变量
在A.sh脚本中定义的变量能被B.sh脚本所访问
语法 export 变量名
demo1.sh:
#!/bin/bash
var_env="张三"
export var_env
sh demo2.shdemo2.sh
#!/bin/bash
echo "输出环境变量var_env,值为${var_env}"在终端执行sh demo1.sh
总结:
局部变量定义:变量名=变量值
常量定义:readonly 变量名
全局变量定义:export 变量名
查询变量:$变量名 、${变量名}
删除变量:unset 变量名
4.特殊变量
Shell 提供了一些预定义的特殊变量,如:
$0
:脚本的名称。$1
,$2
, ...:脚本的参数。$#
:脚本参数的数量。$?
:最后执行的命令的退出状态。$!
:最后创建的后台进程的进程ID。
使用示例:
创建demo3.sh文件,文件内容如下:
#!/bin/bash
echo "输出脚本名称: $0"
echo "输出脚本第一个参数: $1"
echo "输出脚本第二个参数: $2"
echo "输出脚本第三个参数: $3"echo "当参数超过十个的时候,10以后的参数要用花括号括起来,包括第十个: ${10}"# 添加后台运行的命令
sleep 10 &echo "最后执行命令的退出状态: $?"
echo "最后创建的后台进程的进程ID: $!"
四、字符串
常见字符串格式
1.单引号
任何字符串都会原样输出,在字符串中拼接变量是无效的
2.双引号
其中包含了变量,那么该变量会被解析得到的值,而不会原样输出
字符串中还可以出现双引号的子字符串,但需要转意
3.不被引号包围的字符串
不被引号包围的字符串中出现变量也会被解析,这一点和双引号" "包围的字符串一样
字符串中不能出现空格,否则空格后面的内容会被当做其他命令解析
4.获取字符串长度
语法:${#变量名}
字符串拼接
1.无符号拼接
2.双引号拼接
3.混合拼接
字符串截取
语法:
注:字符串下标从0开始
五、数组
数组的定义
语法:
arr1=(item1 item2 item3) #方式一,中间以空格隔开arr2=([索引1]=item1 [索引2]=item2) #方式二,自定义索引, = 两边不能有空格
数组的获取
1.通过下标获取数组元素,index从0开始
${arr[index]}
2.获取值的同时赋值给其他变量
item=${arr[index]}
3.使用@或*可以获取数组中的所有元素
${arr[@]}
${arr[*]}
4.获取数组长度
${#arr[@]}
${#arr[*]}
5.获取数组指定元素的字符串长度
${#arr[index]}
数组的拼接
数组的删除
1.删除数组中指定的元素
unset arr[index]
2.删除数组所有元素
unset arr
六、内置命令
Shell 内置命令,就是由 Bash shel 自身提供的命令,而不是文件系统中的可执行脚本文件。
使用type 来确定一个命令是否是内置命令:
type 命令
alias设置别名
当某些内置命令过长,而且又经常使用的时候,我们就可以通过设置别名的形式,把复杂的命令设置成简短的命令,语法如下
alias 别名='命令'
在终端运行alias时,可以查看当前的别名列表:
例如我们给ps -aux设置一个别名:
删除某个别名,语法如下:
unalias 别名
删除当前环境下的所有别名,语法如下:
unalias -a
read读取控制台输入
read命令的作用
read 是 Shell 内置命令,用于从标准输入中读取数据并赋值给变量。如果没有进行重定向,默认就是从终端控制台读取用户输入的数据;如果进行了重定向,那么可以从文件中读取数据。
read的语法如下:
read [-options] [var1 var2...]
options表示选项,如下表所示;var表示用来存储数据的变量,可以有一个也可以有多个。
options和var都是可选的,如果没有提供变量名,那么读取的数据将存到环境变量REPLY中。
$REPLY保存read最后一个读入命令的数据
options支持的参数:
使用read给多个变量赋值
创建一个read1.sh文件,内容如下:
#!/bin/bash
#使用read命令读取数据,要有提示信息“请输入姓名、年龄、爱好”,并且将数据赋值给多个变量
read -p "请输入姓名、年龄、爱好:" name age hobby
echo "姓名${name}"
echo "年龄${age}"
echo "爱好${hobby}"
使用read读取一个字符
创建一个read2.sh文件,内容如下:
#!/bin/bash
#使用read命令读取数据,要有提示信息“您确定要删除这条信息吗?请输入(y/n)”
read -n 1 -p "您确定要删除这条信息吗?请输入(y/n)" char
echo "所输入字符为${char}"
使用read限制时间输入
创建一个read3.sh文件,内容如下:
#!/bin/bash
#使用read命令读取数据,要有提示信息"请输入密码(20秒内):",并且设置限制时间20秒
read -t 20 -sp "请输入密码(20秒内):" pwd1
#输出一个换行
echo
#使用read命令读取数据,要有提示信息"请再次输入密码(20秒内):",并且设置限制时间20秒
read -t 20 -sp "请输入密码(20秒内):" pwd2
#输出一个换行
printf "\n"
#校验两次密码是否一致
if [$pwd1==$pwd2]
thenecho "两次密码一致,验证通过"
elseecho "两次密码不一致,验证失败"
fi
exit退出
在 Shell 脚本中,exit
命令用于立即终止脚本的执行。当 exit
命令被执行时,脚本会停止执行后续命令,并返回一个状态值给调用环境(如父 shell 或操作系统)。这个状态值通常用于指示脚本的退出状态或执行结果
exit
命令的基本语法如下:
exit [n]
- 如果没有参数,
exit
将返回状态值 0,这通常表示成功。 - 如果提供了参数
n
,exit
将返回状态值n
。这个值通常是一个介于 1 到 255 之间的整数,用来表示脚本执行失败或异常的情况。
获取脚本状态码:
echo $?
返回非零状态值的意义
在脚本中返回非零状态值是一个重要的最佳实践,特别是当脚本作为更大工作流的一部分时。这允许调用脚本的程序或 shell 能够根据脚本的返回值采取不同的行动,如重新尝试、记录错误或执行清理操作。
示例:编写shell脚本使用exit 退出,退出时返回一个非0数字状态值,执行脚本文件并打印返回状态值:
#!/bin/bashecho hello
exit 2
declare设置变量属性
declare命令用于声明 shell 变量。可用来声明变量并设置变量的属性,也可用来显示shell函数。若不加上任何参数,则会显示全部的shell变量与函数(与执行set指令的效果相同)。
1.设置变量属性
语法:
declare [+/-][frxiaA][变量名称=设置值]
参数 | 说明 |
---|---|
+/- | "-“可用来指定变量的属性,”+"则是取消变量所设的属性。 |
-f | 仅用显示函数 |
-r | 变量设置成只读 |
-x | 指定变量为环境变量,可以为shell以外的程序来使用 |
-i | [设置值]可以是数值,字符串或运算式。 |
-a | 设置为数组 |
-A | 设置为关联数组(有点像java中的map) |
# 声明一个变量a 为正数变量
declare -i a
a=12 #如果a="aa" 那么打印出来时0#上面也可以简写为
declare -i a=12# 如果非要将a进行赋值为"aa"
declare +i a
a="aa" #这样打印出的aa#也可以设置只读
declare -r a
2.声明关联数组和普通索引数组
新版的bash shell 支持关联数组,关联数组使用字符串作为下标,而不是数字,这样方便我们知道某些内容具体代表什么意义。
关联数组是key-value键值对,有点像是java中的map。
#声明关系数组
declare -A cd
cd["name"]="zhangsan"
cd["age"]=12#声明索引数组
declare -a cd='([0]="a" [1]="b" [2]="c")' //声明数组变量
let命令
let
是 Bash shell 中的一个内置命令,用于执行算术运算。它主要用于简单的整数运算,如加、减、乘、除以及位运算等。let
命令可以简化在 shell 脚本中进行算术计算的过程,尤其当涉及到变量赋值和表达式计算时。
基本语法
let
的基本语法如下:
let "expression"
或者,
let expression
在第二种形式中,let
和 expression
之间没有引号,这是因为在 let
内部不需要使用引号来包裹表达式。
示例
让我们看一些 let
命令的使用示例:
简单的算术运算
#!/bin/bash
a=5
b=3
let "c=a+b"
echo $c
这段脚本将输出 8
。
变量赋值
let
也可以直接用于变量赋值:
#!/bin/bash
let "result=5+3"
echo $result
这将输出 8
。
位运算
let
还支持位运算:
#!/bin/bash
let "x=5 & 3"
echo $x
这将输出 1
,因为 5
和 3
在二进制下分别是 101
和 011
,按位与的结果是 001
。
自增和自减
let
也支持自增和自减操作:
#!/bin/bash
let "counter=0"
let "counter++"
echo $counter
这将输出 1
。
注意事项
let
默认执行整数运算,不支持浮点数。- 当使用
let
进行赋值时,无需在变量名前添加$
符号。 let
命令的输出不会自动打印,如果需要输出结果,需要通过echo
或其他命令显示地输出。
七、运算符
shell支持多种运算符,包括:
- 算数运算符
- 关系运算符
- 布尔运算符
- 字符串运算符
- 文件测试运算符
原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。
算术运算符
下表列出了常用的算术运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
+ | 加法 | `expr $a + $b` 结果为 30。 |
- | 减法 | `expr $a - $b` 结果为 -10。 |
* | 乘法 | `expr $a \* $b` 结果为 200。 |
/ | 除法 | `expr $b / $a` 结果为 2。 |
% | 取余 | `expr $b % $a` 结果为 0。 |
= | 赋值 | a=$b 把变量 b 的值赋给 a。 |
== | 相等。用于比较两个数字,相同则返回 true。 | [ $a == $b ] 返回 false。 |
!= | 不相等。用于比较两个数字,不相同则返回 true。 | [ $a != $b ] 返回 true。 |
注意:
- 条件表达式要放在方括号之间,并且要有空格,例如: [$a==$b] 是错误的,必须写成 [ $a == $b ]。
- 乘号(*)前边必须加反斜杠(\)才能实现乘法运算;
- 在 MAC 中 shell 的 expr 语法是:$((表达式)),此处表达式中的 “*” 不需要转义符号 “\”
示例:
编写expr1.sh脚本文件,内容如下:
#!/bin/bash
a=10
b=20val=`expr $b % $a`
echo "b % a : $val"if [ $a == $b ]
thenecho "a 等于 b"
fi
if [ $a != $b ]
thenecho "a 不等于 b"
fi
运行结果如下:
1.扩展
对于算数运算,我们也可以这样的写法:
1.使用[]
#!/bin/bash
num1=10
num2=16echo "num1+num2="$[num1+num2]
echo "num1-num2="$[num1-num2]
echo "num1*num2="$[num1*num2]
echo "num1/num2="$[num1/num2]
echo "num2/num1="$[num2/num1]
运行结果:
num1+num2=26
num1-num2=-6
num1*num2=160
num1/num2=0
num2/num1=1
注意:做除法运算的时候只显示整数部分,不显示小数部分。
2.使用(())
#!/bin/bash
num1=10
num2=16echo "num1+num2="$(($num1+$num2))
echo "num1-num2="$(($num1-$num2))
echo "num1*num2="$((num1*num2))
echo "num1/num2="$((num1/num2))
echo "num2/num1="$((num2/num1))
运行结果:
注意:
- 使用(())可以不用$符来获取变量值,它会自动解析变量
- 变量与符号之间可以不用空格
关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
下表列出了常用的关系运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返回 0。 | [ $a -eq $b ] 返回 1。 |
-ne | 检测两个数是否不相等,不相等返回 0。 | [ $a -ne $b ] 返回 0。 |
-gt | 检测左边的数是否大于右边的,如果是,则返回 0。 | [ $a -gt $b ] 返回 1。 |
-lt | 检测左边的数是否小于右边的,如果是,则返回 0。 | [ $a -lt $b ] 返回 0。 |
-ge | 检测左边的数是否大于等于右边的,如果是,则返回 0。 | [ $a -ge $b ] 返回 1。 |
-le | 检测左边的数是否小于等于右边的,如果是,则返回 0。 | [ $a -le $b ] 返回 0。 |
布尔运算符
下表列出了常用的布尔运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
! | 非运算,表达式为 true 则返回 false,否则返回 true。 | [ ! false ] 返回 true。 |
-o | 或运算,有一个表达式为 true 则返回 true。 | [ $a -lt 20 -o $b -gt 100 ] 返回 true。 |
-a | 与运算,两个表达式都为 true 才返回 true。 | [ $a -lt 20 -a $b -gt 100 ] 返回 false。 |
注意:这里的0代表为true,1代表为false
4. 逻辑运算符
以下介绍 Shell 的逻辑运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
&& | 逻辑的 AND | [[ $a -lt 100 && $b -gt 100 ]] 返回 false |
|| | 逻辑的 OR | [[ $a -lt 100 || $b -gt 100 ]] 返回 true |
示例:
#!/bin/basha=10
b=20if [[ $a -lt 100 && $b -gt 100 ]]
thenecho "返回 true"
elseecho "返回 false"
fiif [[ $a -lt 100 || $b -gt 100 ]]
thenecho "返回 true"
elseecho "返回 false"
fi
执行结果如下:
区别于联系:
[] 与[[ ]] 的区别:
- [[ ]] 中逻辑组合可以使用 && || 符号
- 而[] 里面逻辑组合可以用 -a -o
字符串运算符
下表列出了常用的字符串运算符,假定变量 a 为 “abc”,变量 b 为 “efg”:
运算符 | 说明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 true。 | [ $a = $b ] 返回 false。 |
!= | 检测两个字符串是否不相等,不相等返回 true。 | [ $a != $b ] 返回 true。 |
-z | 检测字符串长度是否为0,为0返回 true。 | [ -z $a ] 返回 false。 |
-n | 检测字符串长度是否不为 0,不为 0 返回 true。 | [ -n “$a” ] 返回 true。 |
$ | 检测字符串是否为空,不为空返回 true。 | [ $a ] 返回 true。 |
注意:这里的0代表为true,1代表为false
文件测试运算符
Shell 中的文件测试运算符允许你在脚本中测试文件的各种属性。这些运算符通常在方括号 [
和 ]
或者 [[
和 ]]
之间使用,并且用于 if 语句或 while 循环中进行条件判断。
在 Linux 系统中,文件类型多种多样,每种类型的文件都有其特定的功能和用途。以下是 Linux 中常见的几种文件类型:
-
普通文件(Regular Files): 这是最常见的文件类型,包含数据、文本、配置信息、程序代码等。在文件系统中表现为一个没有特殊标志的图标或文件名前没有特殊字符。
-
目录文件(Directory Files): 目录也是一种特殊的文件,用于组织其他文件和目录。在命令行中,目录通常以开头的斜杠
/
或点字符.
表示。 -
设备文件(Device Files): 设备文件分为两种:
- 块设备文件(Block Devices):如硬盘驱动器、光盘驱动器等,它们可以随机访问数据。
- 字符设备文件(Character Devices):如串行端口、打印机等,它们提供顺序的数据流。
-
符号链接(Symbolic Links): 又称为软链接,类似于 Windows 中的快捷方式,指向另一个文件或目录的引用。符号链接本身是一个文件,其中包含目标文件的路径。
-
硬链接(Hard Links): 指向同一文件的多个文件名。硬链接直接指向文件的 inode(文件系统中的节点),而不是文件名。删除一个硬链接不会删除文件本身,直到最后一个硬链接被删除,文件才会被删除。
-
套接字文件(Socket Files): 用于进程间通信(IPC),可以是本地通信(Unix Domain Socket)或网络通信(TCP/IP Socket)。
-
管道文件(FIFOs或命名管道): FIFO 是一种特殊的文件,用于进程间通信,它创建了一个数据通道,可以被读取和写入。
-
特殊文件: 包括各种特殊目的的文件,比如
/proc
和/sys
目录下的文件,它们提供了对内核和硬件的访问。
在 Linux 命令行中,可以通过 ls -l
命令查看文件的详细信息,文件类型会显示在最左侧的字符中。例如,-
表示普通文件,d
表示目录,l
表示符号链接,b
表示块设备,c
表示字符设备,p
表示管道文件,s
表示套接字文件。
文件测试运算符用于检测 Unix 文件的各种属性。
属性检测描述如下:
操作符 | 说明 | 举例 |
---|---|---|
-b file | 检测文件是否是块设备文件,如果是,则返回 true。 | [ -b $file ] 返回 false。 |
-c file | 检测文件是否是字符设备文件,如果是,则返回 true。 | [ -c $file ] 返回 false。 |
-d file | 检测文件是否是目录,如果是,则返回 true。 | [ -d $file ] 返回 false。 |
-f file | 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 | [ -f $file ] 返回 true。 |
-g file | 检测文件是否设置了 SGID 位,如果是,则返回 true。 | [ -g $file ] 返回 false。 |
-k file | 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 | [ -k $file ] 返回 false。 |
-p file | 检测文件是否是有名管道,如果是,则返回 true。 | [ -p $file ] 返回 false。 |
-u file | 检测文件是否设置了 SUID 位,如果是,则返回 true。 | [ -u $file ] 返回 false。 |
-r file | 检测文件是否可读,如果是,则返回 true。 | [ -r $file ] 返回 true。 |
-w file | 检测文件是否可写,如果是,则返回 true。 | [ -w $file ] 返回 true。 |
-x file | 检测文件是否可执行,如果是,则返回 true。 | [ -x $file ] 返回 true。 |
-s file | 检测文件是否为空(文件大小是否大于0),不为空返回 true。 | [ -s $file ] 返回 true。 |
-e file | 检测文件(包括目录)是否存在,如果是,则返回 true。 | [ -e $file ] 返回 true |
expr命令详解
`expr` 是一个在 Unix 和类 Unix 系统(如 Linux)中使用的命令行工具,用于执行基本的数学和字符串表达式的解析和计算。`expr` 命令可以处理算术运算、字符串操作以及一些逻辑运算。
算术运算
`expr` 支持以下算术运算:
- 加法:`+`
- 减法:`-`
- 乘法:`*`
- 整除:`/`
- 求余:`%`
例如,计算两个数的和:
expr 5 + 3
字符串操作
`expr` 可以用来进行字符串的比较和截取:
- 比较字符串是否相等:`expr index string1 string2`
- 计算字符串的长度:`expr length string`
- 截取字符串:`expr substr string start end`
例如,获取字符串的长度:
expr length "Hello, world!"截取字符串的一部分:
expr substr "Hello, world!" 7 6
bc命令详解
Bash shell内置了对整数运算的支持,但是并不支持浮点运算,而 linux bc(basic calculator)命令可以很方便的进行浮点运算.bc命令是Linux简单的计算器,能进行进制转换与计算。能转换的进制包括十六进制、十进制、八进制、二进制等。可以使用的运算符号包括(+)加法、(-)减法、(*)乘法、()除法、(^)指数、(%)余数等。
语法:
bc [options] [参数]
options
- -i:强制进入交互式模式;
- -l:定义使用的标准数学库;
- -w:对POSIX bc的扩展给出警告信息;
- -q:不打印正常的GNU bc环境信息;
- -v:显示指令版本信息;
- -h:显示指令的帮助信息。
示例:
更多内容请参考:05.Shell计算命令:bc命令详解-互动式的数学运算_哔哩哔哩_bilibili
八、流程控制语句
if...else语句
语法:
if condition
thencommand1 command2...commandN
elsecommand
fiif condition1
thencommand1
elif condition2
then command2
elsecommandN
fi
if else 的 [...] 判断语句中大于使用 -gt,小于使用 -lt。
if [ "$a" -gt "$b" ]; then...
fi
如果使用 ((...)) 作为判断语句,大于和小于可以直接使用 > 和 <。
if (( a > b )); then...
fi
示例:
#!/bin/bash
a=10
b=20
if [ $a == $b ]
thenecho "a 等于 b"
elif (( $a > $b ))
thenecho "a 大于 b"
elif [ $a -lt $b ]
thenecho "a 小于 b"
elseecho "没有符合的条件"
fi
运行结果:
for语句
语法:
for var in item1 item2 ... itemN
docommand1command2...commandN
done
示例:
#!/bin/bash
for loop in 1 2 3 4 5
doecho "The value is: $loop"
done
运行结果:
while语句
语法:
while condition
docommand
done
示例:
#!/bin/bash
int=1
while(( $int<=5 ))
doecho $intlet "int++"
done
运行结果:
until 语句
until 循环执行一系列命令直至条件为 true 时停止。
until 循环与 while 循环在处理方式上刚好相反。
一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。
until 语法格式:
until condition
docommand
done
condition 一般为条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环。
以下实例我们使用 until 命令来输出 0 ~ 9 的数字:
#!/bin/bash
int=1
while(( $int<=5 ))
doecho $intlet "int++"
done
运行结果:
case ... esac
case ... esac 为多选择语句,与其他语言中的 switch ... case 语句类似,是一种多分支选择结构,每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行结束,跳出整个 case ... esac 语句,esac(就是 case 反过来)作为结束标记。
可以用 case 语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。
case ... esac 语法格式如下:
case 值 in
模式1)command1command2...commandN;;
模式2)command1command2...commandN;;
esac
case 工作方式如上所示,取值后面必须为单词 in,每一模式必须以右括号结束。取值可以为变量或常数,匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;。
取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。
下面的脚本提示输入 1 到 4,与每一种模式进行匹配:
#!/bin/bash
echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in1) echo '你选择了 1';;2) echo '你选择了 2';;3) echo '你选择了 3';;4) echo '你选择了 4';;*) echo '你没有输入 1 到 4 之间的数字';;
esac
运行结果:
跳出循环
在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell 使用两个命令来实现该功能:break 和 continue。
1.break 命令
break 命令允许跳出所有循环(终止执行后面的所有循环)。
下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,需要使用break命令。
#!/bin/bash
while :
doecho -n "输入 1 到 5 之间的数字:"read aNumcase $aNum in1|2|3|4|5) echo "你输入的数字为 $aNum!";;*) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"break;;esac
done
2.continue
continue 命令与 break 命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。
对上面的例子进行修改:
#!/bin/bash
while :
doecho -n "输入 1 到 5 之间的数字: "read aNumcase $aNum in1|2|3|4|5) echo "你输入的数字为 $aNum!";;*) echo "你输入的数字不是 1 到 5 之间的!"continueecho "游戏结束";;esac
done
select语句
在 Bash shell 脚本中,select
命令提供了一种简单的菜单选择机制,允许用户从一组选项中做出选择。这对于创建交互式的脚本非常有用,可以用于构建命令行界面(CLI)应用或菜单驱动的脚本。
语法:
select NAME in LIST; do COMMANDS; done
示例:
#!/bin/bashoptions=("Option 1" "Option 2" "Exit")select opt in "${options[@]}"; docase $opt in"Option 1")echo "You chose option 1.";;"Option 2")echo "You chose option 2.";;"Exit")break;;*) echo "Invalid option. Please select again." ;;esac
done
运行结果:
九、函数
自定义函数
语法:
[ function ] funname [()]{action;[return int;]}
说明:
- 1、可以带 function fun() 定义,也可以直接 fun() 定义,不带任何参数。
- 2、参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return 后跟数值 n(0-255).
下面的例子定义了一个函数并进行调用:
#!/bin/bash
demoFun(){echo "Hello World!"
}
echo "-----函数开始执行-----"
demoFun
echo "-----函数执行完毕-----"
运行结果:
下面定义一个带有 return 语句的函数:
#!/bin/bashfunWithReturn(){echo "这个函数会对输入的两个数字进行相加运算..."echo "输入第一个数字: "read aNumecho "输入第二个数字: "read anotherNumecho "两个数字分别为 $aNum 和 $anotherNum !"return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"
运行结果:
函数返回值在调用该函数后通过 $? 来获得。
注意:所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。
注意: return 语句只能返回一个介于 0 到 255 之间的整数,而两个输入数字的和可能超过这个范围。
要解决这个问题,您可以修改 return 语句,直接使用 echo 输出和而不是使用 return:
funWithReturn(){echo "这个函数会对输入的两个数字进行相加运算..."echo "输入第一个数字: "read aNumecho "输入第二个数字: "read anotherNumsum=$(($aNum + $anotherNum))echo "两个数字分别为 $aNum 和 $anotherNum !"echo $sum # 输出两个数字的和
}
在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数...,当参数超过10个,获取的参数的方式为${10},${11}...
带参数的函数示例:
#!/bin/bashfunWithParam(){echo "第一个参数为 $1 !"echo "第二个参数为 $2 !"echo "第十个参数为 $10 !"echo "第十个参数为 ${10} !"echo "第十一个参数为 ${11} !"echo "参数总数有 $# 个!"echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73
运行结果:
十、输入/输出重定向
输入输出重定向是 Unix/Linux shell 中一个非常强大的功能,它允许你改变命令的输入源或输出目的地,从而实现对数据流的控制。输入输出重定向可以让你避免不必要的屏幕输出,将数据保存到文件,或将数据从文件读入命令,甚至在多个命令之间传递数据。
重定向命令列表如下:
命令 | 说明 |
---|---|
command > file | 将输出重定向到 file。 |
command < file | 将输入重定向到 file。 |
command >> file | 将输出以追加的方式重定向到 file。 |
n > file | 将文件描述符为 n 的文件重定向到 file。 |
n >> file | 将文件描述符为 n 的文件以追加的方式重定向到 file。 |
n >& m | 将输出文件 m 和 n 合并。 |
n <& m | 将输入文件 m 和 n 合并。 |
<< tag | 将开始标记 tag 和结束标记 tag 之间的内容作为输入。 |
输出重定向
重定向一般通过在命令间插入特定的符号来实现。特别的,这些符号的语法如下所示:
command1 > file1
上面这个命令执行command1然后将输出的内容存入file1。
注意任何file1内的已经存在的内容将被新内容替代。如果要将新内容添加在文件末尾,请使用>>操作符。
示例:
重定向输入
我们先来学习一下wc命令,Linux的wc命令可以用来统计文件的字节个数、行数、单词数
语法:
wc [options] [文件名]
options选项如下:
在了解上述命令后,我们继续学习重定向输入:
一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:
- 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
- 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
- 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。
默认情况下,command > file 将 stdout 重定向到 file,command < file 将stdin 重定向到 file。
如果希望 stderr 重定向到 file,可以这样写:
command 2>file
如果希望 stderr 追加到 file 文件末尾,可以这样写:
command 2>>file
2 表示标准错误文件(stderr)。
如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写:
command >> file 2>&1
如果希望对 stdin 和 stdout 都重定向,可以这样写:
command < file1 >file2
command 命令将 stdin 重定向到 file1,将 stdout 重定向到 file2。
示例:
参考文章:Shell 教程 | 菜鸟教程 (runoob.com)
相关文章:

万字长文带你入门shell编程(超详细)
一、概述 Shell 是计算机操作系统中用户与操作系统内核之间的接口层,它提供了一种方式让用户能够通过命令行界面(CLI)与操作系统交互。Shell 可以被视为一个命令解释器,它接收用户输入的命令,解析这些命令,…...

音质提升秘籍:专业音频剪辑软件汇总
现在欣赏传输音频文件比以前简单多了,这些音频的质量也影响了听众的体验与感受。所以使用一些靠谱的音频剪辑工具处理音频能让你的音频文件呈现更好的效果。 1.福昕音频剪辑 链接直达>>https://www.foxitsoftware.cn/audio-clip/ 这是一款电脑端软件。别看…...

idea配置
在我们使用idea的时候会进行配置主要就idea编译器的下载,maven资源管理器,Tomcat服务器 在IntelliJ IDEA的官网进入http://www.jetbrains.com/idea/ 如图如果你是大学生的话一般学校会有相关的激活码直接选择左边的.exe文件下载,直接的就是企…...

将 WinForms 中的 Panel 替换为 WPF 的 WindowsFormsHost 元素
要将 WinForms 中的 Panel 替换为 WPF 的 WindowsFormsHost 元素,你需要执行以下步骤:1. 添加对 WindowsFormsIntegration 的引用:确保你的项目引用了 WindowsFormsIntegration 和 PresentationCore、PresentationFramework 程序集࿰…...

C++ ---- vector的底层原理剖析及其实现
vector 一、定义二、常用接口及模拟实现三、vector迭代器失效问题四、使用memcpy拷贝会出现的问题五、二维数组vector<vector< T >> vv 一、定义 vector 是 C 标准模板库(Standard Template Library, STL)中的一个非常有用的容器。它是一个…...

跑酷视频素材去哪里下载?哪里有跑酷游戏视频素材?
在这个快节奏的视觉时代,跑酷视频因其惊险和动感吸引了众多动作爱好者和视频创作者的目光。如果您正在寻找高质量的跑酷视频素材来丰富您的项目,无论是增强视频的视觉冲击力还是展现跑酷运动的魅力,以下几个推荐的网站将是您的理想选择。 蛙…...

Centos 7配置问题
在VMWare12上面安装Centos 7 Linux虚拟机,在切换到命令界面时,需要登录用户名和密码,但发现输入用户后有字符显示,但是密码没有。 经过一系列查看后,发现这个是Linux的一种机制,即当你输入密码时不显示&…...

浮动IP(Floating IP)计费;OpenStack算力共享;OpenStack实现资源虚拟化;算力调度策略
目录 浮动IP(Floating IP)计费 浮动IP的定义与作用 计费中的浮动IP数据 浮动IP在计费中的作用 OpenStack算力共享 一、OpenStack在算力共享中的角色 二、OpenStack与算力共享的结合方式 三、实际应用案例 算力调度策略 算力计费策略 OpenStack实现资源虚拟化 1.虚…...

Android 源码单独编译Settings模块
一般我们编译源码,只需要在源码的根目录下执行三个命令就行 . build/envsetup.sh 或者source build/envsetup.sh lunch 选择编译目标 make -j60make 不带参数的编译方式是直接编译整个系统,我们也可以使用make带模块名或者使用mmm等命令单独编译某个模块。 首先找到对应模块…...

虚拟机类加载机制
与那些编译时需要进行连接的语言不同,在java语言中,类型的 动态加载:编写一个面向接口的应用程序,可以等到运行时再指定其实现类。 类加载:加载-连接-初始化-使用-卸载 一个类被调用时,会将其class文件从…...

Google Earth Engine(GEE)——逐月筛选影像,并给影像集合添加新的属性
简介 导入影像集合首先,您需要导入您要筛选的影像集合。使用Google Earth Engine的ImageCollection类来导入影像集合。您可以通过ee.ImageCollection()函数传递影像集合的ID或通过一个ee.ImageCollection()对象导入影像集合。 例如,导入Landsat 8卫星每月影像集合的代码如下…...

如何从智联招聘网站快速抓取职位详情?两大技巧揭秘
摘要: 本文将揭秘如何利用Python爬虫技术,高效且合法地从智联招聘网站抓取职位详情信息。通过实战示例,展现两大核心技巧,助你在大数据时代抢占先机,为你的市场分析、人才研究提供强大支持。 一、引言:数据…...

C#知识|ini文件操作
哈喽,你好啊,我是雷工! 本节学习ini文件的操作,之前练习过通过ini文件导出采集模块的配置信息,然后再另一个模块中导入配置信息,如此实现快速配置采集模块,提高效率。 以下为学习笔记。 01 认识ini文件 ini文件是一种文件格式,类似txt,xml等, ini文件在上位机开发中使…...

Linux系统学习之路
一、Linux基础训练 https://mp.weixin.qq.com/mp/appmsgalbum?actiongetalbum&__bizMzUxNjMwMzk4MQ&scene1&album_id3544800080551952390&count3#wechat_redirect...

DNS介绍与部署-Day 01
1. 什么是DNS DNS(Domain Name System)域名系统,是一种采用客户端/服务器机制,负责实现计算机名称与IP地址转换的系统。DNS作为一种重要的网络服务,既是Internet工作的基础,同时在企业内部网络中也得到了广…...

python 图片爬虫记录
感谢大家的点赞。再补充一点。 对于这个 url https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEqB5nighYsMZE7kexaVNJfxy3OkRutNEKatksw9u5f-ckHNROLzFyx2Uty3zYWNEaeOmzsljGr3eARiDWaM9DM8G2hPuPf8uZP0NO3kNUCnM2Cjb3ZKtLhJDBwqeR4ElpJ7ID5_wIHGQ/s200 这个url最…...

本地安装Llama3.1与LobeChat可视化UI界面并实现远程访问大模型实战
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

MSF回弹木马在Ubuntu中测试
1.创建文件 网站地址为192.168.30.129 首先在Ubuntu中use/local/nginx/sbin路径下创建一个PHP文件; 如图所示: 然后进入网页下载PHP文件如图所示: 什么都不显示说明这个没有问题就怕访问失败。 2.使用蚂键连接网站 在蚂键中的URL地址栏中…...

大数据等保测评
在当今数字化浪潮汹涌澎湃的时代,大数据已成为企业和组织创新发展的核心驱动力。然而,随着大数据应用的日益广泛和深入,其安全问题也日益凸显。大数据等保测评作为保障大数据安全的重要手段,具有至关重要的意义。 大数据的特点决定…...

CSS对元素的分类
文章目录 概述置换元素/非置换元素置换元素非置换元素 行内元素/块级元素/行内块级元素行内元素块级元素行内块级元素 概述 CSS从两个维度上将HTML元素进行了分类: 从元素内容的表现形式上,将元素分为:置换元素、非置换元素。从元素自身的显…...

力扣第五十四题——螺旋矩阵
内容介绍 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 示例 1: 输入:matrix [[1,2,3],[4,5,6],[7,8,9]] 输出:[1,2,3,6,9,8,7,4,5]示例 2: 输入:matrix …...

中创算力:以知识产权转化运用促进高质量发展
创新是引领发展的第一动力,保护知识产权就是保护创新。为深入实施知识产权公共服务普惠工程,促进知识产权公共服务更好服务高水平科技,国家知识产权局发布关于全面提升知识产权公共服务效能的指导意见。 在政策落地过程中,如何精…...

C语言9~10 DAY(合集)
数组的概念 什么是数组 数组是相同类型,有序数据的集合。 数组的特征 数组中的数据被称为数组的元素,是同构的 数组中的元素存放在内存空间里 (char player_name[6]:申请在内存中开辟6块连续的基于char类型的变量空间) 衍生概念&#x…...

【Kubernetes】应用的部署(一):金丝雀部署
应用的部署(一):金丝雀部署 在项目迭代开发过程中,经常需要对应用进行上线部署。上线部署策略主要有 3 种:金丝雀部署、蓝绿部署 和 滚动部署。 金丝雀部署 也被叫作 灰度部署。金丝雀部署过程:先让一部分…...

1.面试准备篇
筛选简历 找实习用处不大 简历注意事项 注意职业技能和项目经历 职业技能 黄金位置 针对性 引导面试官提问 只写会的 不会的不能写 项目描述 主要设计… 展示指标 找练手项目 来源:Gitee 或者github 主要关注点:功能实现、常见问题、系统设计 面试过程 一面…...

Spring: try-catch 是否还会回滚
问题出现: try-catch 语句 依旧会抛出如下错误 org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnlyat org.springf…...

spdlog日志库--基础介绍
文章目录 1. 简介1.1. spdlog代码特点1.2. 说明1.3. spdlog架构 2. spdlog的安装2.1. 使用包管理器安装2.2. 使用源码安装2.3. 仅使用头文件 3. 相关概念3.0 常用的头文件3.1. level_enum3.2. sink3.3. logger3.4 格式输出3.5 对齐方式3.6 截断3.7 字符串格式化fmt 4. 特性4.1.…...

【网络】网络编程套接字(二)
网络编程套接字(二) 文章目录 1.单执行流的TCP网络程序1.1服务端创建套接字1.2服务端绑定1.3服务端监听1.4服务端获取链接1.5服务端处理请求1.6客户端创建套接字1.7客户端连接服务器1.8客户端发起请求 2.多进程版的TCP网络程序2.1单执行流的弊端2.2多进…...

1.1、centos stream 9安装Kubernetes v1.30集群 环境说明
最近正在学习kubernetes,买了一套《Kubernetes权威指南 从Docker到Kubernetes实践全接触(第六版)》这本书讲得很好,上下两册,书中k8s的版本是V1.29,目前官网最新版本是v1.30。强烈建议大家买一套看看。 Kubernetes官网地址&#x…...

Redis3
目录 什么是缓存穿透?怎么解决? 什么是缓存雪崩?怎么解决? 如何保证数据库和缓存的数据一致性? 如何保证Redis服务高可用? 哨兵的作用 Redis虚拟槽分区有什么优点? 为什么Redis集群最大槽…...