编程基础
程序组成
程序
一组计算机能识别和执行的指令,运行于电子计算机上,满足人们某种需求的信息化工具。它以某些程 序设计语言编写,运行于某种目标结构体系上。
算法
算法是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,代表着用系统的方法描述解决 问题的策略机制。
数据结构
数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素 的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。
数据
是程序的核心,程序为数据提供服务,也是互联网公司最重要的资产。
程序编程风格
面向过程
-
做一件事情,排出个步骤,第一步干什么,第二步干什么,如果出现情况A,做什么处理,如果出 现了情况B,做什么处理
-
问题规模小,可以步骤化,按部就班处理
-
以指令为中心,数据服务于指令
-
C,shell
面向对象
-
将编程看成是一个事物,对外界来说,事物是直接使用的,不用关心事物内部的情况。而编程就是 设置事物能够完成功能。
-
一种认识世界、分析世界的方法论。将万事万物抽象为各种对象
-
类是抽象的概念,是万事万物的抽象,是一类事物的共同特征的集合
-
对象是类的具体实现,是一个实体
-
问题规模大,复杂系统
-
以数据为中心,指令服务于数据
-
java,C#,python,golang等
编程逻辑处理方式
三种处理逻辑:
-
顺序执行:程序按从上到下顺序执行
-
选择执行:程序执行过程中,根据条件的不同,进行选择不同分支继续执行
-
循环执行:程序执行过程中需要重复执行多次某段语句
shell 脚本语言的基本用法
shell 脚本的用途
-
将简单的命令组合完成复杂的工作,自动化执行命令,提高工作效率
-
减少手工命令的输入,一定程度上避免人为错误
-
将软件或应用的安装及配置实现标准化
-
用于实现日常性的,重复性的,非交互式的运维工作,如:文件打包压缩备份,监控系统运行状态 并实现告警等
shell 脚本基本结构
shell是基于过程式、解释执行的语言。
shell脚本是包含一些命令或声明,并符合一定格式的文本文件。
一个shell脚本文件中主要包含以下内容
-
各种系统命令的组合
-
数据存储:变量、数组
-
表达式:a + b
-
控制语句:if
格式要求:首行shebang机制
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
#!/usr/bin/ruby
#!/usr/bin/lua
shell脚本创建过程
-
用编辑器创建新文件,首行必须是 shell 声明(shebang),编辑完成后保存退出
-
添加可执行权限
-
运行脚本
#新建文件
[root@ubuntu2204 ~]# vim test.sh
#!/bin/bash
echo "hello world"
#加可执行权限
[root@ubuntu2204 ~]# chmod +x test.sh
#执行,相对路径
[root@ubuntu2204 ~]# ./test.sh
hello world
#执行,绝对路径
[root@ubuntu2204 ~]# /root/test.sh
hello world
#相当于执行命令,会在 $PATH 路径下去找,找不到就报错
[root@ubuntu2204 ~]# test.sh
test.sh: command not found
shell 脚本注释规范
一般要注明作者,创建(修改)时间,文件名,版本号,该程序的功能及作用,目地,版权信息,作者联系 方式等
配置vim 自动生成注释
[root@ubuntu2204 ~]# vim .vimrc
set nu
set ts=4
autocmd BufNewFile *.sh exec ":call SetTitle()"
func SetTitle()
if expand("%:e") == 'sh'
call setline(1,"#!/bin/bash")
call setline(2,"#")
call setline(3,"#****************************************************")
call setline(4,"#Author: jose")
call setline(5,"#QQ: 123456")
call setline(6,"#Date: ".strftime("%Y-%m-%d"))
call setline(7,"#FileName: ".expand("%"))
call setline(8,"#URL: http://www.baidu.com")
call setline(9,"#Description: test")
call setline(10,"#Copyright(C): ".strftime("%Y")." All right")
call setline(11,"#***************************************************")
call setline(12,"")
call setline(13,"")
call setline(14,"")
endif
endfunc
autocmd BufNewFile * normal G
第一个 shell 脚本
#当前进程中执行
root@ubuntu2204 ~]# . hello.sh
hello, world
Hello, world!
#子进程中执行
root@ubuntu2204 ~]# ./hello.sh
hello, world
Hello, world!
#本地执行远程脚本 - 脚本文件在远程主机,在本机执行并在本机生效,执行结果影响的是本机
root@ubuntu2204 ~]# curl http://10.0.0.157/test.sh -s | bash
hello, world
Hello, world!
root@ubuntu2204 ~]# curl http://10.0.0.157/test.sh 2>/dev/null | bash
hello, world
Hello, world!
root@ubuntu2204 ~]# wget -qO - http://10.0.0.157/test.sh | bash
hello, world
Hello, world!
#在远程主机运行本地脚本 - 脚本文件在本地,在远程主机执行并生效,执行结果影响的是远程主机,但终端中的输出在本地显示
#本地执行
root@ubuntu2204 ~]# bash test2.sh
10.0.0.150
#远程主机上执行
root@ubuntu2204 ~]# ssh root@10.0.0.157 /bin/bash < test2.sh
root@10.0.0.157's password:
10.0.0.157
shell 脚本调试
1.执行前先做语法检查 此选项只能检测脚本中的语法错误,不能检测命令错误,也不会执行脚本
bash -n test.sh
2.调试并执行 逐行输出命令,并输出执行结果
bash -x test.sh
总结:脚本错误常见的有三种
-
语法错误:会导致后续的命令不继续执行,可以用 bash -n 检查错误,提示的出错行数不一定是准 确的
-
命令错误:默认后续的命令还会继续执行,用 bash -n 无法检查出来 ,可以使用 bash -x 进行观察
-
逻辑错误:只能使用 bash -x 进行观察
变量
变量表示命名的内存空间,将数据放在内存空间中,通过变量名引用,获取数据
数据要存在内存空间中,而内存空间又是通过内存地址来访问的,但内存地址一般是16进制的编号;
为了方便使用,就有了变量名,当访问一个变量时,实际是访问其对应的内存地址的那块内存空间;
变量类型
变量类型:
-
内置变量,如:PS1,PATH,UID,HOSTNAME,$$,BASHPID,PPID,$?,HISTSIZE
-
用户自定义变量
不同的变量存放的数据不同,决定了以下
-
数据存储方式
-
参与的运算
-
表示的数据范围
变量数据类型:
-
字符
-
数值:整型、浮点型,bash 不支持浮点数
-
布尔
-
指针
-
结构体:自定义的复合类型的数据类型
-
......
变量定义和引用
变量的生效范围等标准划分变量类型
普通变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell 进程均无效
环境变量:生效范围为当前shell进程及其子进程
本地变量:生效范围为当前shell进程中某代码片断,通常指函数
变量赋值:
name='value'
#value 可以是以下多种形式
name='root' #直接字串
name="$USER" #变量引用
name=`COMMAND` #命令引用
name=$(COMMAND) #命令引用
#注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除
变量引用:
$name
${name} #标准写法
弱引用和强引用
-
"$name" 弱引用,其中的变量引用会被替换为变量值
-
'$name' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
保留格式
[root@ubuntu2204 ~]# seq 5
1
2
3
4
5
[root@ubuntu2204 ~]# NUM=`seq 5`
[root@ubuntu2204 ~]# echo $NUM
1 2 3 4 5
[root@ubuntu2204 ~]# echo "$NUM"
1
2
3
4
5
显示已定义的所有变量:
set
删除变量:
unset <name>
环境变量
-
可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量
-
一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程
-
一般只在系统配置文件中使用,在脚本中较少使用
变量声明和赋值:
#声明并赋值
export name=VALUE
declare -x name=VALUE
#或者分两步实现
name=VALUE
export name
显示所有环境变量:
env
printenv
export
declare -x
查看指定进程的环境变量
cat /proc/$PID/environ
只读变量
只读变量:只能声明定义,但后续不能修改和删除,即常量
声明只读变量:
readonly name
declare -r name
查看只读变量
readonly [-p]
declare -r
位置变量
位置变量:在bash shell中内置的变量,在脚本代码中调用通过命令行传递给脚本的参数
$1,$2,... #对应第1个、第2个等参数,shift [n]换位置
$0 #命令本身,包括路径
$* #传递给脚本的所有参数,全部参数合为一个字符串
$@ #传递给脚本的所有参数,每个参数为独立字符串
$# #传递给脚本的参数的个数
#清空所有位置变量
set --
$*和$@的区别
$*和$@ 都表示传递给函数或脚本的所有参数。它们之间的区别在于:
-
$*将所有参数从整体上看做一份数据,不把每个参数都看做独立的。
-
$@仍然将每个参数都看作一份数据,彼此之间是独立的。
退出状态码变量
进程执行后,将使用变量 $? 保存状态码的相关数字,不同的值反应成功或失败,$?取值范例 0-255
$? #0代表成功,1-255代表失败
用户可以在脚本中使用以下命令自定义退出状态码
exit [n]
注意:
-
脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字
-
如果exit后面无数字,终止退出状态取决于exit命令前面命令执行结果
-
如果没有exit命令,即未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后 一 条命令的状态码
展开命令行
展开命令执行顺序
把命令行分成单个命令词
展开别名
展开大括号的声明{}
展开波浪符声明 ~
命令替换$() 和 ``
再次把命令行分成命令词
展开文件通配符*、?、[abc]等等
准备I/0重导向 <、>
运行命令
防止扩展
\ #反斜线 会使随后的字符按原意解释
'' #单引号 防止所有扩展
"" #双引号 也可防止扩展,但是以下情况例外 $
变量扩展
`` #反引号,命令替换
\ #反斜线,禁止单个字符扩展
! #叹号,历史命令替换
脚本安全和 set
set 命令:可以用来定制 shell 环境
$- 变量
选项 | 含义 | 备注 |
---|---|---|
h | hashall | 开启hash表缓存外部命令路径 |
i | interactive-comments | 表示当前是交互是shell |
m | monitor | 开启监控模式,可通过 Job control来控制进程的停止、继续,后台 或者前台执行等 |
B | braceexpand | 是否支持大括号扩展 |
H | history | 是否可用 ! 快速展开history命令 |
#查看命令行下的配置
[root@ubuntu2204 ~]# echo $-
himBHs
#示例:#关闭hash缓存功能
[root@ubuntu22:~]# echo $-
himBHs
[root@ubuntu22:~]# hash
hits command
1 /usr/bin/mesg
1 /usr/bin/seq
[root@ubuntu22:~]# set +h
[root@ubuntu22:~]# echo $-
imBHs
[root@ubuntu22:~]# hash
-bash: hash: hashing disabled
[root@ubuntu22:~]# set -h
[root@ubuntu22:~]# echo $-
himBHs
[root@ubuntu22:~]# hash
hits command
1 /usr/bin/mesg
1 /usr/bin/seq
set 命令实现脚本安全
字符 | 作用 |
---|---|
u | 开启此项,在使用一个没有声明的变量时,会报错,并且终止程序,同 set -o nounset |
e | 开启此项,命令返回非0就退出,不再继续执行后面的代码,同 set -o errexit |
o | set -o 显示所有; set -o option 开启 option 项; set +o option 关闭 option 项 |
x | set -x 打印命令及其参数 |
-
-u 在扩展一个没有设置的变量时,显示错误信息, 等同set -o nounset
-
-e 如果一个命令返回一个非0退出状态值(失败)就退出, 等同set -o errexit
-
-o option 显示,打开或者关闭选项 显示选项:set -o 打开选项:set -o 选项 关闭选项:set +o 选 项
-
-x 当执行命令时,打印命令及其参数,类似 bash -x
格式化输出 printf
相当于增强版的 echo, 实现丰富的格式化输出
格式
printf format args...
常用格式替换符
替换符 | 功能 |
---|---|
%s | 字符串 |
%d,%i | 十进制整数 |
%f | 浮点格式 |
%c | ASCII字符,即显示对应参数的第一个字符 |
%b | 相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转义 |
%o | 八进制值 |
%u | 不带正负号的十进制 |
%x | 十六进制的值(a-f) |
%X | 十六进制值(A-F) |
%% | 表示%本身 |
说明:
%[N]s # N表示输出宽度,不够补空格 -N 表示左对齐
%[0][N]d # 0表示宽度不够时在左边补0,N表示输出宽度
%[.N]f # .N 表示保留的小数位
常用转义字符
转义符 | 功能 |
---|---|
\a | 警告字符,通常为ASCII的BEL字符 |
\b | 后退 |
\f | 换页 |
\n | 换行 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ | 表示\本身 |
算术运算
Shell允许在某些情况下对算术表达式进行求值,比如:let和declare 内置命令,(( ))复合命令和算术扩 展。求值以固定宽度的整数进行,不检查溢出,尽管除以0 被标记为错误。运算符及其优先级,关联性 和值与C语言相同。以下运算符列表分组为等优先级运算符级别。级别按降序排列优先。
注意:bash 只支持整数,不支持小数
+ - #addition, subtraction加、减
* / % #multiplication, division, remainder, %表示取模,即取余数,示例:9%4=1,5%3=2
i++ i-- #variable post-increment and post-decrement变量的后递增和后递减
++i --i #variable pre-increment and pre-decrement变量的预递增和预递减
= *= /= %= += -= <<= >>= &= ^= |= #assignment赋值
- + #unary minus and plus
! ~ #logical and bitwise negation
** #exponentiation 乘方,即指数运算
<< >> #left and right bitwise shifts
<= >= < > #comparison
== != #equality and inequality
& #bitwise AND
| #bitwise OR
^ #bitwise exclusive OR
&& #logical AND
|| #logical OR
expr?expr:expr #conditional operator
expr1 , expr2 #comma
乘法符号有些场景中需要转义
实现算术运算:
let var=expression
((var=expression))
var=$[expression]
var=$((expression))
var=$(expr arg1 arg2 ...)
declare -i var=number
echo expression|bc
#expr 命令
#表达式中间要有空格
[root@ubuntu2204 ~]# expr 10+20
10+20
[root@ubuntu2204 ~]# expr 10 + 20
30
[root@ubuntu2204 ~]# expr 10 \* 20
200
#内核的随机数生成器变量
$RANDOM #取值范围:0-32767
echo -e "\033[1;$[RANDOM%7+31]mhello\033[0m" #随机字体颜色
增强型赋值:
+= # i+=10 相当于 i=i+10
-= # i-=j 相当于 i=i-j
*=
/=
%=
++ # i++,++i 相当于 i=i+1
-- # i--,--i 相当于 i=i-1
逻辑运算
与或非
true, false
bool值 | 二进制表示 | 说明 |
---|---|---|
true | 1 | 真 |
false | 0 | 假 |
与:&
& 和0相与结果为0,和1相与结果保留原值, 一假则假,全真才真
变量1 | 变量2 | 与运算 | 与运算结果 |
---|---|---|---|
0 | 0 | 0&0 | 0 |
0 | 1 | 0&1 | 0 |
1 | 0 | 1&0 | 0 |
1 | 1 | 1&1 | 1 |
或:|
| 和1相或结果为1,和0相或结果保留原值,一真则真,全假才假
变量1 | 变量2 | 与运算 | 与运算结果 |
---|---|---|---|
0 | 0 | 0|0 | 0 |
0 | 1 | 0|1 | 1 |
1 | 0 | 1|0 | 1 |
1 | 1 | 1|1 | 1 |
非:!
变量 | 运算 | 非运算结果 |
---|---|---|
1 | !1 | 0 |
0 | !0 | 1 |
异或:^
异或的两个值,相同为假,不同为真。两个数字X,Y异或得到结果Z,Z再和任意两者之一X异或,将得 出另一个值Y
变量1 | 变量2 | 异或运算 | 与运算结果 |
---|---|---|---|
0 | 0 | 0^0 | 0 |
0 | 1 | 0^1 | 1 |
1 | 0 | 1^0 | 1 |
1 | 1 | 1^1 | 0 |
短路运算
短路与 &&
command1值 | command2值 | 短路与运算 | 短路与运算结果 |
---|---|---|---|
true | true | cmd1 && cmd2 | true |
true | false | cmd1 && cmd2 | false |
false | cmd1 && cmd2 | false |
当 cmd1 的结果为 false 时,整个表达式就是 false, cmd2 不参与运算,这就是所谓的短路
短路或 ||
command1值 | command2值 | 短路与运算 | 短路与运算结果 |
---|---|---|---|
true | cmd1 || cmd2 | true | |
false | true | cmd1 || cmd2 | true |
false | false | cmd1 || cmd2 | false |
当 cmd1 的结果为 true 时,整个表达式就是 true, cmd2 不参与运算,这就是所谓的短路
短路与和或组合
command1 值 | command2 值 | command3值 | 短路运算 | 短路与运算结果 |
---|---|---|---|---|
true | true | true | cmd1 && cmd2 || cmd3 | true |
true | true | false | cmd1 && cmd2 || cmd3 | true |
true | false | true | cmd1 && cmd2 || cmd3 | true |
true | false | false | cmd1 && cmd2 || cmd3 | false |
false | true | true | cmd1 && cmd2 || cmd3 | true |
false | true | false | cmd1 && cmd2 || cmd3 | false |
false | false | true | cmd1 && cmd2 || cmd3 | true |
false | false | false | cmd1 && cmd2 || cmd3 | false |
当cmd1 的结果为true时,会执行 cmd2;
当cmd1 的结果为false时,会执行 cmd3;
cmd1 || cmd2 && cmd3 这种语法是错误的,不使用;
条件测试命令
条件测试:
判断某需求是否满足,需要由测试机制来实现,专用的测试表达式需要由测试命令辅助完成测试过程, 实现评估布尔声明,以便用在条件性环境下进行执行
若真,则状态码变量 $? 返回0
若假,则状态码变量 $? 返回1
条件测试命令
test expr
[ arg... ] #同 test
[[ expression ]] #增加版的[],支持[],支持扩展正则表达式和通配符
注意:[] 中的表达式,前后要有空格
常用选项:
文件判断相关
-a FILE #如果文件存在则为真
-b FILE #如果文件为块特殊文件则为真
-c FILE #如果文件为字符特殊文件则为真
-d FILE #如果文件为目录则为真
-e FILE #如果文件存在则为真
-f FILE #如果文件存在且为常规文件则为真
-g FILE #如果文件的组属性设置打开则为真
-h FILE #如果文件为符号链接则为真
-L FILE #如果文件为符号链接则为真
-k FILE #如果文件的粘滞 (sticky) 位设定则为真
-p FILE #如果文件为命名管道则为真
-r FILE #如果当前用户对文件有可读权限为真
-s FILE #如果文件存在且不为空则为真
-S FILE #如果文件是套接字则为真
-t FD #如果文件描述符在一个终端上打开则为真
-u FILE #如果文件设置了SUID特殊权限则为真
-w FILE #如果当前用户对文件有可写权限为真
-x FILE #如果当前用户对文件有可执行权限为真
-O FILE #如果当前用户是文件属主为真
-G FILE #如果当前用户对文件属组为真
-N FILE #如果文件上次被读取之后修改过则为真
FILE1 -nt FILE2 #如果 file1 文件新于 file2 文件 则为真(根据修改日期)
FILE1 -ot FILE2 #如果 file1 文件旧于 file2 文件则为真
FILE1 -ef FILE2 #如果 file1 文件是 file2 文件的硬链接则为真
字符串判断相关
-z STRING #判断字符串是否为空,为空则为真
-n STRING #如果字符串不为空则为真
STRING #同上
#两个字符串变量比较,一定要有空格,如果没有空格,就变成赋值了
STRING1 = STRING2 #如果 string1 和 string2 字符串相同则为真
STRING1 != STRING2 #如果 string1 和 string2 字符串不相同则为真
STRING1 < STRING2 #只比较第一个字符,以字母表顺序来比较,string1在string2 之前则为真,< 要转义
STRING1 > STRING2 #只比较第一个字符,以字母表顺序来比较,string1在string2 之后则为真, > 要转义
数学相关
#数字相关 格式 arg1 OP arg2
-eq #等于
-ne #不等于
-lt #小于
-le #小于等于
-gt #大于
-ge #大于等于
#算术表达式比较
== #相等
!= #不相等
<= #小于或等于
>= #大于或等于
< #小于
> #大于
其他
o OPTION #如果在shell 中开启了某项,则为真
-v VAR #如果变量被设置为为真
-R VAR #如果变量被设置且被引用则为真
! EXPR #表达式结果取反
EXPR1 -a EXPR2 #如果 expr1 和 expr2 都为真则为真 &&
EXPR1 -o EXPR2 #如果 expr1 和 expr2 有一个为真则为真
变量测试
范例:判断变量是否被定义
[root@ubuntu2204 ~]# unset x
[root@ubuntu2204 ~]# test -v x
[root@ubuntu2204 ~]# echo $?
1
[root@ubuntu2204 ~]# x=10
[root@ubuntu2204 ~]# test -v x
[root@ubuntu2204 ~]# echo $?
0
[root@ubuntu2204 ~]# y=
[root@ubuntu2204 ~]# test -v y
[root@ubuntu2204 ~]# echo $?
0
#注意 [ ] 中需要空格,否则会报下面错误
[root@ubuntu2204 ~]# [-v name]
-bash: [-v: command not found
[root@ubuntu2204 ~]# [ -v name ]
[root@ubuntu2204 ~]# echo $?
0
数值测试
#示例
[root@ubuntu2204 ~]# i=10
[root@ubuntu2204 ~]# j=8
[root@ubuntu2204 ~]# [ $i -lt $j ]
[root@ubuntu2204 ~]# echo $?
1
[root@ubuntu2204 ~]# [ $i -gt $j ]
[root@ubuntu2204 ~]# echo $?
0
[root@ubuntu2204 ~]# [ i -gt j ]
-bash: [: i: integer expression expected
字符串测试
test和 [ ] 字符串测试用法
-z STRING #判断字符串是否为空,为空则为真
-n STRING #如果字符串不为空则为真
STRING #同上
#两个字符串变量比较,一定要有空格,如果没有空格,就变成赋值了
STRING1 = STRING2 #如果 string1 和 string2 字符串相同则为真
STRING1 != STRING2 #如果 string1 和 string2 字符串不相同则为真
STRING1 < STRING2 #只比较第一个字符,以字母表顺序来比较,string1在string2 之前则为真,< 要转义
STRING1 > STRING2 #只比较第一个字符,以字母表顺序来比较,string1在string2 之后则为真, > 要转义
[[ ]] 字符串测试用法
[[ expression ]] 用法
== #左侧字符串是否和右侧的PATTERN相同
#注意:此表达式用于[[ ]]中,PATTERN为通配符
=~ #左侧字符串是否能够被右侧的正则表达式的PATTERN所匹配
#注意: 此表达式用于[[ ]]中为扩展的正则表达式
建议:当使用正则表达式或通配符使用[[ ]],其它情况一般使用 [ ]
文件测试
#文件是否不存在
[root@ubuntu2204 ~]# [ -a /etc/nologin ]
[root@ubuntu2204 ~]# echo $?
1
[root@ubuntu2204 ~]# ! [ -a /etc/nologin ]
[root@ubuntu2204 ~]# echo $?
0
#文件是否存在
[root@ubuntu2204 ~]# [ -a /etc/issue ]
[root@ubuntu2204 ~]# echo $?
0
#取反后结果却没有变化
[root@ubuntu2204 ~]# [ ! -a /etc/issue ]
[root@ubuntu2204 ~]# echo $?
0
[root@ubuntu2204 ~]#! [ -a /etc/issue ]
[root@ubuntu2204 ~]# echo $?
1
#文件是否存在
[root@ubuntu2204 ~]#! [ -e /etc/issue ]
[root@ubuntu2204 ~]# echo $?
1
#此为推荐写法
[root@ubuntu2204 ~]# [ ! -e /etc/issue ]
[root@ubuntu2204 ~]# echo $?
1
[root@ubuntu2204 ~]# [ -d /etc ]
[root@ubuntu2204 ~]# echo $?
0
[root@ubuntu2204 ~]# [ -d /etc/issue ]
[root@ubuntu2204 ~]# echo $?
1
[root@ubuntu2204 ~]# [ -L /bin ]
[root@ubuntu2204 ~]# echo $?
0
[root@ubuntu2204 ~]# [ -L /bin/ ]
[root@ubuntu2204 ~]# echo $?
1
文件权限测试:
注意:最终结果由用户对文件的实际权限决定,而非文件属性决定
[root@ubuntu2204 ~]# [ -w /etc/shadow ]
[root@ubuntu2204 ~]# echo $?
0
[root@ubuntu2204 ~]# [ -x /etc/shadow ]
[root@ubuntu2204 ~]# echo $?
1
[root@ubuntu2204 ~]# [ -w test.txt ]
[root@ubuntu2204 ~]# echo $?
0
[root@ubuntu2204 ~]# chattr +i test.txt
[root@ubuntu2204 ~]# lsattr test.txt
----i---------e------- test.txt
[root@ubuntu2204 ~]# [ -w test.txt ]
[root@ubuntu2204 ~]# echo $?
1
[root@ubuntu2204 ~]# chattr -i test.txt
[root@ubuntu2204 ~]# [ -w test.txt ]
[root@ubuntu2204 ~]# echo $?
0
关于 () 和 {}
( cmd1;cmd2;... ) 和 { cmd1;cmd2;...; } 都可以将多个命令组合在一起,批量执行
( list ) 会开启子shell,并且list中变量赋值及内部命令执行后,将不再影响后续的环境
{ list; } 不会开启子shell, 在当前shell中运行,会影响当前shell环境,左侧要有空格,右侧要有; 结束
组合测试条件
第一种方式
[ EXPRESSION1 -a EXPRESSION2 ] #并且,EXPRESSION1和EXPRESSION2都是真,结果才为真
[ EXPRESSION1 -o EXPRESSION2 ] #或者,EXPRESSION1和EXPRESSION2只要有一个真,结果就为真
[ ! EXPRESSION ] #取反
说明: -a 和 -o 需要使用测试命令进行,[[ ]] 不支持
第二种方式
条件表达式
COMMAND1 && COMMAND2 #并且,短路与,代表条件性的AND THEN
#如果COMMAND1成功,将执行COMMAND2,否则,将不执行COMMAND2
COMMAND1 || COMMAND2 #或者,短路或,代表条件性的OR ELSE
#如果COMMAND1 成功,将不执行COMMAND2,否则,将执行COMMAND2
! COMMAND #非,取反