type
status
date
slug
summary
tags
password
category
Property
Jan 28, 2023 06:33 AM
icon
3.1 概论3.1.1 学习技巧3.1.2 脚本示例3.1.3 运行方式3.2 注释3.2.1 单行注释3.2.2 多行注释3.3 变量3.3.1 定义变量3.3.2 使用变量3.3.3 只读变量3.3.4 删除变量3.3.5 变量类型3.3.6 字符串3.4 默认变量3.4.1 文件参数变量3.4.2 其他参数相关变量3.5 数组3.5.1 定义3.5.2 读取数组中某个元素的值3.5.3 读取整个数组3.5.4 数组长度3.6 expr 命令3.6.1 表达式说明3.6.2 字符串表达式3.6.3 整数表达式3.6.4 逻辑表达式3.7 read 命令3.8 echo 命令3.8.1 显示普通字符串3.8.2 显示转义字符3.8.3 显示变量3.8.4 显示换行3.8.5 显示不换行3.8.6 显示结果定向至文件3.8.7 原样输出字符串,不进行转义或取变量(用单引号)3.8.8 显示命令执行结果3.9 printf 命令3.10 test 命令 与 判断符号 []3.10.1 逻辑运算符&&和||3.10.2 test 命令3.10.3 文件类型判断3.10.4 文件权限判断3.10.5 整数间的比较3.10.6 字符串比较3.10.7 多重条件判定3.10.8 判断符号[]3.11 判断语句3.11.1 if..then 形式3.11.2 单层 if3.11.3 单层 if-else3.11.4 多层 if-elif-elif-else3.11.5 case..esac 形式3.12 循环语句3.12.1 for…in…do…done3.12.2 for((…;…;…)) do…done3.12.3 while…do…done3.12.4 until…do…done3.12.5 break 命令3.12.6 continue 命令3.12.7 死循环的处理方式3.13 函数3.13.1 不获取return值和stdout值3.13.2 获取return值和stdout值3.13.3 函数的输入参数3.13.4 函数内的局部变量3.14 exit 命令3.15 文件重定向3.15.1 重定向命令列表3.15.2 输入和输出重定向3.15.3 同时重定向stdin和stdout3.16 引入外部脚本3.17 习题课homework_0homework_1homework_2homework_3homework_4
3.1 概论
shell
是我们通过命令与操作系统沟通的语言shell
脚本可以直接在命令行中执行,也可以将一套逻辑组织成一个文件,方便复用Ac Terminal
中的命令行可以看成是一个shell
脚本在逐行执行Linux
中常见的shell
脚本有很多种,常见的有:ㅤㅤ●ㅤ
Bourne Shell
(/usr/bin/sh
或/bin/sh
)ㅤㅤ●ㅤ
Bourne Again Shell
(/bin/bash
)ㅤㅤ●ㅤ
C Shell
(/usr/bin/csh
)ㅤㅤ●ㅤ
K Shell
(/usr/bin/ksh
)ㅤㅤ●ㅤ
zsh
ㅤㅤ●ㅤ
...
Linux
系统中一般默认使用bash
,所以接下来讲解bash
中的语法文件开头需要写
#! /bin/bash
,指明bash
为脚本解释器3.1.1 学习技巧
ㅤㅤ不要死记硬背,遇到含糊不清的地方,可以在
Ac Terminal
里实际运行一遍3.1.2 脚本示例
新建一个
test.sh
文件,内 c容如下:3.1.3 运行方式
作为可执行文件
用解释器执行
3.2 注释
3.2.1 单行注释
每行中
#
之后的内容均是注释3.2.2 多行注释
格式:
其中
EOF
可以替换成其它任意字符串 例如:3.3 变量
3.3.1 定义变量
定义变量,不需要加
$
符号, 例如:3.3.2 使用变量
使用变量,需要加上
$
符号,或者${}
符号 花括号是可选的, 主要是为了帮助解释器识别变量边界3.3.3 只读变量
使用
readonly
或者declare
可以将变量变为只读3.3.4 删除变量
unset
可以删除变量3.3.5 变量类型
1. 自定义变量(局部变量)子进程不能访问的变量
2. 环境变量(全局变量)子进程可以访问的变量
自定义变量改成环境变量:
环境变量改为自定义变量:
目前
tmux
中就是一个bash
3.3.6 字符串
字符串可以用单引号,也可以用双引号,也可以不用引号
单引号和双引号的区别:
单引号总的内容会原样输出,不会执行、不会取变量;
双引号中的内容可以用执行、可以取变量;不用引号与双引号一样
获取字符串长度
提取子串
3.4 默认变量
3.4.1 文件参数变量
在执行
shell
脚本时,可以向脚本传递参数$1
第一个参数,$2
是第二个参数,以此类推特殊的
$0
是文件名(包含路径)
ㅤㅤ例如:创建文件
test.sh
然后执行该脚本:
3.4.2 其他参数相关变量
参数 | 说明 |
$# | 代表文件传入的参数个数,如上例中值为4 |
$* | 由所有参数构成的用空格隔开的字符串,如上例中值为 "$1 $2 $3 $4" |
$@ | 每个参数分别用双引号括起来的字符串,如上例中值为 "$1" "$2" "$3" "$4" |
$$ | 脚本当前运行的进程ID |
$? | 上一条命令的退出状态(注意不是 stdout ,而是exit code )0表示正常退出,其他值表示错误 |
$(command) | 返回 command 这条命令的stdout (可嵌套) |
command | 返回 command 这条命令的stdout (不可嵌套) |
3.5 数组
数组中可以存放多个不同类型的值,只支持一维数组,初始化时不需要指明数组大小
数组下标从0开始
3.5.1 定义
数组用小括号表示,元素之间用空格隔开。例如:
array=(1 abc "def" zst)
也可以直接定义数组中某个元素的值:
3.5.2 读取数组中某个元素的值
格式:
${array[index]}
例如:
3.5.3 读取整个数组
格式:
例如:
3.5.4 数组长度
类似于字符串
只会计算被赋值了的下标
例如:
3.6 expr 命令
expr
命令用于求表达式的值,格式为:expr 表达式
3.6.1 表达式说明
●ㅤ用空格隔开每一项
●ㅤ用反斜杠放在
shell
特定的字符前面(发现表达式运行错误时,可以试试转义)●ㅤ对包含空格和其他特殊字符的字符串要用引号括起来
●ㅤ
expr
会在stdout
中输出结果。如果为逻辑关系表达式,则结果为真,stdout
为1,否则为0●ㅤ
expr
的exit code
:如果为逻辑关系表达式,则结果为真,exit code
为0,否则为13.6.2 字符串表达式
●ㅤ
length String
返回String
的长度●ㅤ
index String CharSet
ㅤㅤ
CharSet
中任意单个字符在String
中最前面的字符位置,下标从1开始ㅤㅤ如果在
String
中完全不存在CharSet
中的字符,则返回0●ㅤ
substr String Position length
ㅤㅤ返回
String
字符串中从Position
开始,长度最大为length
的子串ㅤㅤ如果
Position
或length
为负数,0或非数值,则返回空字符串示例:
3.6.3 整数表达式
expr
支持普通的算数操作,算术表达式优先级低于字符串表达式,高于逻辑关系表达式ㅤㅤ●ㅤ
+ -
:加减运算。两端参数会转换为整数,如果转换失败则报错ㅤㅤ●ㅤ
* / %
:乘、除、取模运算。两端参数会转换为整数,如果转换失败则会报错ㅤㅤ●ㅤ
()
:可以改变优先级,但需要用反斜杠转义或者是''
进行转义示例:
3.6.4 逻辑表达式
●ㅤ
|
:ㅤㅤ如果第一个参数非空且非0,不会计算第二个参数,
ㅤㅤ如果第一个参数非空且非0,则返回第一个参数的值,
ㅤㅤ否则如果第二个参数非空且非0,则返回第二个参数的值,
ㅤㅤ否则返回0。
●ㅤ
&
:ㅤㅤ如果两个参数都非空且非0,则返回第一个参数,否则返回0。如果第一个参为0或为空,则不会计算第二个参数。
●ㅤ
< <= = == != >= >
:ㅤㅤ比较两端的参数,如果为
true
,则返回1,否则返回0。ㅤㅤ
==
是=
的同义词。expr
首先尝试将两端参数转换为整数,并做算术比较,如果转换失败,则按字符集排序规则做字符比较。●ㅤ
()
:可以改变优先级,但需要用反斜杠转义或者是''
进行转义示例:
3.7 read 命令
read
命令用于从标准输入中读取单行数据当读取到文件结束符时,
exit code
为1,否则为0参数说明:
ㅤㅤ●ㅤ
p
:后面可以接提示信息ㅤㅤ●ㅤ
t
:后面跟秒数,定义输入字符的等待时间,超出等待时间后会自动忽略此命令实例:
3.8 echo 命令
echo
用于输出字符串。命令格式:echo String
3.8.1 显示普通字符串
3.8.2 显示转义字符
3.8.3 显示变量
3.8.4 显示换行
3.8.5 显示不换行
3.8.6 显示结果定向至文件
3.8.7 原样输出字符串,不进行转义或取变量(用单引号)
3.8.8 显示命令执行结果
3.9 printf 命令
printf
命令用于格式化输出,类似于C/C++
中的printf
函数默认不会在字符串末尾添加换行符
命令格式:
printf format-string [arguments...]
用法示例
脚本内容:
输出结果:
3.10 test 命令 与 判断符号 []
3.10.1 逻辑运算符&&和||
●ㅤ
&&
表示与,||
表示或●ㅤ二者具有短路原则:
ㅤㅤ
expr1 && expr2
:当expr1
为假时,直接忽略expr2
ㅤㅤ
expr1 || expr2
:当expr1
为真时,直接忽略expr2
●ㅤ表达式的
exit code
为0,表示真;为非零,表示假。(与C/C++
中的定义相反)3.10.2 test 命令
在命令行中输入
main test
,可以查看test
命令的用法test
命令用于判断文件类型,以及对变量做比较test
命令用exit code
返回结果,而不是使用stdout
0表示真,非0表示假
例如:
3.10.3 文件类型判断
命令格式:
test -e filename # 判断文件是否存在
测试参数 | 代表意义 |
-e | 文件是否存在 |
-f | 是否为文件 |
-d | 是否为目录 |
3.10.4 文件权限判断
命令格式:
test -r filename # 判断文件是否可读
测试参数 | 代表意义 |
-r | 文件是否可读 |
-w | 文件是否可写 |
-x | 文件是否可执行 |
-s | 是否为非空文件 |
3.10.5 整数间的比较
命令格式:
test $a -eq $b # a是否等于b
测试参数 | 代表意义 |
-eq | a 是否等于 b |
-ne | a 是否不等于 b |
-gt | a 是否大于 b |
-lt | a 是否小于 b |
-ge | a 是否大于等于 b |
-le | a 是否小于等于 b |
3.10.6 字符串比较
测试参数 | 代表意义 |
test -z String | 判断 String 是否为空,如果为空,则返回 true |
test -n String | 判断 String 是否非空,如果非空,则返回 true (-n可以省略) |
test str1 == str2 | 判断 str1 是否等于 str2 |
test str1 != str2 | 判断 str1 是否不等于 str2 |
3.10.7 多重条件判定
命令格式:
test -r filename -a -x filename
测试参数 | 代表意义 |
-a | 两条件是否同时成立 |
-o | 两条件是否至少一个成立 |
! | 取反。如 test ! -x file ,当file 不可执行时,返回true |
3.10.8 判断符号[]
[]
和test
用法几乎一模一样,更常用于if
语句中另外
[[]]
是[]
的加强版,支持的特性更多例如:
注意:
●ㅤ
[]
内的每一项都要用空格隔开●ㅤ中括号内的变量,最好用双引号括起来
●ㅤ中括号内的常熟,最好用单或双引号括起来
例如:
3.11 判断语句
3.11.1 if..then 形式
类似于
C/C++
中的if-else
语句3.11.2 单层 if
命令格式:
示例:
3.11.3 单层 if-else
命令格式:
示例:
3.11.4 多层 if-elif-elif-else
命令格式:
示例:
3.11.5 case..esac 形式
类似于
C/C++
中的switch
语句命令格式:
示例:
3.12 循环语句
3.12.1 for…in…do…done
命令格式:
示例1,输出a 2 cc,每个元素一行:
示例2,输出当前路径下的所有文件名,每个文件名一行:
示例3,输出1-10:
示例4,使用
{1..10}
或者 {a..z}
:3.12.2 for((…;…;…)) do…done
命令格式:
示例,输出1-10,每个数占一行:
3.12.3 while…do…done
命令格式:
示例,文件结束符为
Ctrl + d
,输入文件结束符后read
指令返回false
。3.12.4 until…do…done
当条件为真时结束。
命令格式:
示例,当用户输入
yes
或者YES时结束,否则一直等待读入。3.12.5 break 命令
跳出当前一层循环,注意与
C/C++
不同的是:break
不能跳出case
语句。示例:
该示例每读入非
EOF
的字符串,会输出一遍1-7。该程序可以输入
Ctrl + d
文件结束符来结束,也可以直接用Ctrl + c
杀掉该进程。3.12.6 continue 命令
跳出当前循环。
示例:
该程序输出1-10中的所有奇数。
3.12.7 死循环的处理方式
如果
AC Terminal
可以打开该程序,则输入Ctrl + c
即可。否则可以直接关闭进程:
ㅤㅤ●ㅤ使用
top
命令找到进程的PID
ㅤㅤ●ㅤ输入
kill -9 PID
即可关掉此进程3.13 函数
bash
中的函数类似于C/C++
中的函数,但return
的返回值与C/C++
不同,返回的是exit code
,取值为0-255
,0
表示正常结束。如果想获取函数的输出结果,可以通过
echo
输出到stdout
中,然后通过$(function_name)
来获取stdout
中的结果。函数的
return
值可以通过$?
来获取。命令格式:
3.13.1 不获取return
值和stdout
值
示例:
3.13.2 获取return
值和stdout
值
不写
return
时,默认return 0
。示例:
3.13.3 函数的输入参数
在函数内,
$1
表示第一个输入参数,$2
表示第二个输入参数,依此类推。注意:函数内的
$0
仍然是文件名,而不是函数名。示例:
3.13.4 函数内的局部变量
可以在函数内定义局部变量,作用范围仅在当前函数内。
可以在递归函数中定义局部变量。
命令格式:
local 变量名=变量值
例如:
第一行为函数内的name变量,第二行为函数外调用name变量,会发现此时该变量不存在。
3.14 exit 命令
exit
命令用来退出当前shell
进程,并返回一个退出状态;使用$?
可以接收这个退出状态。exit
命令可以接受一个整数值作为参数,代表退出状态。如果不指定,默认状态值是0
。exit
退出状态只能是一个介于0~255
之间的整数,其中只有0
表示成功,其它值都表示失败。示例:
创建脚本
test.sh
,内容如下:3.15 文件重定向
每个进程默认打开3个文件描述符:
ㅤㅤ●ㅤ
stdin
标准输入,从命令行读取数据,文件描述符为0
ㅤㅤ●ㅤ
stdout
标准输出,向命令行输出数据,文件描述符为1
ㅤㅤ●ㅤ
stderr
标准错误输出,向命令行输出数据,文件描述符为2
可以用文件重定向将这三个文件重定向到其他文件中。
3.15.1 重定向命令列表
命令 | 说明 |
command > file | 将 stdout 重定向到file 中 |
command < file | 将 stdin 重定向到file 中 |
command >> file | 将 stdout 以追加方式重定向到file 中 |
command n> file | 将文件描述符 n 重定向到file 中 |
command n>> file | 将文件描述符 n 以追加方式重定向到file 中 |
3.15.2 输入和输出重定向
3.15.3 同时重定向stdin
和stdout
创建
bash
脚本:3.16 引入外部脚本
类似于
C/C++
中的include
操作,bash
也可以引入其他文件中的代码。语法格式:
示例:
创建
test1.sh
,内容为:然后创建
test2.sh
,内容为:执行命令:
3.17 习题课
homework_0
进入
homework_0
文件夹,编写自动完成 lesson_1
作业的脚本 helper.sh
。要求:ㅤㅤ[1] 当前目录下仅包含
helper.sh
ㅤㅤ[2]
helper.sh
具有可执行权限ㅤㅤ[3] 在任意路径依次执行下列命令后,
lesson_1
的作业可以得到满分:ㅤㅤㅤㅤ1)
homework 1 create
ㅤㅤㅤㅤ2)
/home/acs/homework/lesson_3/homework_0/helper.sh
homework_1
进入
homework_1
文件夹,编写脚本 check_file.sh
。要求:ㅤㅤ[1] 当前目录下仅包含
check_file.sh
。ㅤㅤ[2]
check_file.sh
具有可执行权限。ㅤㅤ[3]
check_file.sh
接收一个传入参数。格式为 ./check_file.sh file
ㅤㅤ[4] 判断传递参数,分别在标准输出中输出如下内容(不包括双引号):
ㅤㅤㅤㅤ1)如果传入参数个数不是
1
,则输出一行:arguments not valid
,然后退出,退出状态等于 1
。ㅤㅤㅤㅤ2)如果
file
文件 不存在
,则输出一行:not exist
,然后退出,退出状态等于 2
。ㅤㅤㅤㅤ3)如果
file
文件 存在
,则输出分别进行如下 5
个判断,然后退出,退出状态等于 0
。ㅤㅤㅤㅤ1] 如果
file
为 普通文件
,则输出一行:regular file
ㅤㅤㅤㅤ2] 如果
file
为 目录(文件夹)
,则输出一行:directory
ㅤㅤㅤㅤ3] 如果
file
具有 可读
权限,则输出一行:readable
ㅤㅤㅤㅤ4] 如果
file
具有 可写
权限,则输出一行:writable
ㅤㅤㅤㅤ5] 如果file具有
可执行
权限,则输出一行:executable
homework_2
进入
homework_2
文件夹,编写脚本 main.sh
。要求:ㅤㅤ[1] 当前目录下仅包含
main.sh
ㅤㅤ[2]
main.sh
具有可执行权限ㅤㅤ[3] 该文件从
stdin
(标准输入)中读取一个整数 n
ㅤㅤ[4] 在
stdout
(标准输出)输出斐波那契数列的第 n
项。即:a[0] = 1
, a[1] = 1
, a[i] = a[i - 1] + a[i - 2]
, 求 a[n]
。ㅤㅤ[5] 数据保证
0 <= n <= 20
,脚本不需要判断 n
的合法性。homework_3
进入
homework_3
文件夹,编写脚本 main.sh
。要求:ㅤㅤ[1] 当前目录下仅包含
main.sh
ㅤㅤ[2]
main.sh
具有可执行权限ㅤㅤ[3] 该文件从
stdin
(标准输入)中读取两行整数 n
和 m
ㅤㅤ[4] 在
stdout
(标准输出)中输出 1~n
的按字典序从小到大的顺序数第 m
个全排列,输出一行,用空格隔开所有数,行末可以有多余空格。ㅤㅤ[5] 数据保证
1 <= n <= 10
, 1 <= m <= min(100, n!)
,脚本不需要判断数据的合法性。homework_4
进入
homework_4
文件夹,编写脚本 main.sh
。要求:ㅤㅤ[1] 当前目录下仅包含
main.sh
ㅤㅤ[2]
main.sh
具有可执行权限ㅤㅤ[3]
main.sh
接收两个传入参数。格式为 ./main.sh input_file output_file
ㅤㅤ[4] 从
input_file
中读取一个正整数 n
,然后将前n个正整数的平方和写入 output_file
中ㅤㅤ[5] 数据保证
1 <= n <= 100
,脚本不需要判断所有数据的合法性。