2. Shell 条件测试
重点:
条件测试。
read。
Shell 环境配置。
case。
for。
find。
xargs。
gzip,bzip2,xz。
tar。
sed。
1)位置 变量
位置变量:在 bash Shell 中内置的变量,在脚本代码中调用,通过命令行传递给脚本的参数。
$1, $2, $3 ... "对应第 1 个、第 2 个、 第 3 个等参数"
$0 "命令名称, 包括路径"
$* "传递给脚本的所有参数" 全部参数合为`一个字符串`
$@ "传递给脚本的所有参数" 每个参数为`独立字符串`
$# "传递给脚本的参数的个数"
注意:$@ $* 只在被双引号包起来的时候才会有差异
位置变量是一个非常灵活和方便的功能。
您可以在运行脚本时,通过 在脚本名后面增加参数 来向脚本传递数据。在脚本中,这些参数可以通过 特定的变量名 来获取和处理。
比如 Bash 脚本、Python 脚本等,可以使用 $1、$2、$3 等来获取位置变量,分别表示 第一个、第二个、第三个参数,以此类推。
您可以根据脚本的需求,使用这些参数来执行不同的操作 或传递不同的数据。
示例:
#!/bin/bash
echo 1 arg is $1
echo 2 arg is $2
echo 3 arg is $3
echo all args are $*
echo all args are $@
echo The args number is $#
echo The shname is $0
./hello.sh
./hello.sh one two three

输出第十个参数
echo 10 arg is $10

$10 被识别成 $1 and $0 啦...
因此我们将其书写成 ${10}
echo 10 arg is ${10}

案例 1:
[ 删库跑路命令 rm 的安全实现方式 ]
vim rm.sh
#!/bin/bash
WARNING_COLOR="echo -e \E[1;31m"
END="\E[0m"
DIR=/tmp/`date +%F_%H-%M-%S`
mkdir $DIR
mv $* $DIR
${WARNING_COLOR}Move $* to $DIR $END
chmod +x /root/rm.sh
alias rm=/root/rm.sh
touch {1..10}.txt
rm ~/*.txt

范例
利用软链接 实现同一个脚本不同功能
[ 脚本内判断执行的脚本名称 为 a.sh 即执行A操作,如果 $0 为 b.sh 则执行B操作等 ]
#!/bin/bash
echo the shname is $0
ln -s test.sh a.sh
ln -s test.sh b.sh
bash a.sh
bash b.sh

2)状态码 变量
当我们浏览网页时,有时会看到下图所显示的数字,表示网页的错误信息,我们称为 状态码。
在 Shell 脚本中 也有相似的技术表示程序执行的相应状态。


进程执行后,将使用变量 $? 保存状态码的相关数字,不同的值反应成功或失败,$? 取值范例 0-255。
$? 的值为 0 # 代表成功
$? 的值为 1 - 255 # 代表失败
示范 1
[ echo $? 用于输出 前一条命令的执行状态 ]
# 成功案例
pwd
echo $?
# 失败案例
xxx
echo $?
ll /xxx
echo $?

示范 2
[ 命令书写错误 并不会中断脚本的执行 ]
[ 原因:echo $? 用于输出 前一条命令的执行状态 ]
因此这里的 echo $? 检验的是 echo 456 的 状态代码
echo $?

示范 3
[ 语法书写错误 会中断脚本的执行 ]
因此这里的 echo $? 检验的是 if hostname 的状态代码
echo $?

示范 4
[ 人为指定状态码信息 ]
[ exit 命令 ]
在脚本中,一旦遇到 exit 命令,脚本会立即终止执行。
1. 如果在 exit 命令后面添加一个数字,这将表示 人为修改命令状态码 信息。
2. 如果没有指定数字,命令状态码将 取决于 exit 命令前一条命令 的执行结果。
3. 而如果整个脚本中没有 exit 命令,脚本的命令状态码 将由执行的最后一条命令的状态码决定。
1.sh
hosname
exit 100
2.sh
hosname
exit
3.sh
hosname



注意:exit 为 退出脚本执行 指令
[ 一旦脚本中运行了 exit 命令 脚本后续命令将不再执行 ]
echo 123
exit
echo 456

[ 后续,可使用该操作,判断系统环境是否安装 MySQL 数据库,如果已安装,则 exit 退出脚本 ]
3)Shell 脚本安全
Set 命令:可以用来定制 Shell 环境。
-e 如果一个命令返回一个 非 0 退出状态值 (失败) 就退出
-u 在扩展一个没有设置的变量时,显示错误信息, 等同 set -o nounset
[ 案例 ]
"编写脚本"
#!/bin/bash
DIR=/opt
cd $DIR
rm -rf ./*

此时看上去还没有什么问题,那是因为 /opt 目录真实存在,
但如果 /opt 目录不存在... 然后你即会在运行脚本的目录,执行 rm -rf ./*
bash test.sh
解析:由于 /opt 目录不存在,导致 cd /opt 命令执行失败,因此没有成功进入 /opt 目录,但命令执行失败并不影响脚本后续命令的执行,因此导致在运行脚本的目录下执行了 rm -rf ./* ,如果你所在的目录为 / 那后果可想而知...

[ 因此我们 如何在一个命令执行错误后,不要让他再错上加错呢?]
-e 如果一个命令返回一个 非 0 退出状态值 (失败) 就退出
在脚本中使用 set -e 是指在脚本执行时启用了 Bash Shell 的一个选项,其含义是 "设置错误立即退出"(Set Exit on Error)。
当使用 set -e 时,如果脚本中的任何命令执行失败(即返回非零的退出状态码),则整个脚本会立即终止执行,并返回失败状态码。这可以帮助在脚本中及时发现并处理错误,避免在错误发生后继续执行导致更严重的问题。
需要注意的是,使用 set -e 可能会对脚本的逻辑产生影响,特别是在使用条件语句或管道时。因此,在使用之前,应该仔细考虑脚本的行为和可能出现的错误情况。
#!/bin/bash
set -e
DIR=/opt
cd $DIR
rm -rf ./*

-u 在引用一个 没有定义的变量 时,显示错误信息, 等同 set -o nounset
在脚本中使用 set -u 是指启用了 Bash shell 的一个选项,其含义是 "设置未定义变量报错"(Set Unset Variables to Error)。
当使用 set -u 时,如果脚本中使用了未定义的变量,Bash 会将其视为错误,并立即终止脚本的执行。这可以帮助在脚本中避免意外的错误,因为使用未定义的变量可能导致不可预测的行为。
#!/bin/bash
set -e
DIR=/opt
# 如下命令会执行 rm -rf /* 操作; 由于我们引用了一个未定义的变量
rm -rf $Dir/*
好,删跟了....[ rm -rf 空/* ]

#!/bin/bash
set -e
set -u
DIR=/opt
rm -rf $Dir/*
echo 123

$- 变量
h(hashall):启用该选项后,Shell 会对命令所在的路径进行哈希处理,避免每次都要查询路径。通过使用
set +h 可以关闭该选项。
i(interactive-comments):该选项表明当前 Shell 是交互式Shell。在脚本中,默认是关闭该选项的。
m(monitor):打开监控模式后,可以使用 Job control 来控制进程的停止、继续,以及在后台或前台执行等操作。
B(braceexpand):启用大括号扩展,可以使用大括号来生成多个选项。
H(history):启用该选项后,可以展开历史列表中的命令,通过感叹号 ! 来实现
例如使用
!! 可以返回上一个最近的历史命令,使用
!n 可以返回第n个历史命令。
# 显示当前 shell 的选项标志
echo $-
# 用于在 shell 中关闭 h(hashall)选项
set +h
echo $-


hash

# 演示大括号扩展的用法
echo {1..10}
# 用于在 shell 中关闭 B(braceexpand)选项
set +B
echo $-
# 在关闭了 B 选项后, 这个命令不会进行大括号扩展
echo {1..10}

[ 加回刚才的默认权限 ]
set -h
set -B
echo $-

4)格式化 输出
格式化 输出 Printf
echo 输出命令[ 功能相对较弱 ]
比如:要对输出内容格式化输出,或对输出内容做对齐等操作,echo 就比较乏力了...
1. 因此对于格式化输出或对输出内容做对齐等操作,可以考虑使用更强大的命令,如 printf。
2. printf 命令在格式化输出方面比 echo 更灵活,可以使用格式控制符指定输出的样式,使输出内容更加规整和美观。
printf "指定的格式" "文本1" "文本2"......

常用格式替换符
替换符功能
%s `字符串`
%d,%i `十进制整数`
%f `浮点格式,小数`
%c ASCII字符,即显示对应参数的第一个字符
%b 相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转义。
%o 八进制值
%u 不带正负号的十进制值
%x 十六进制值(a-f)
%X 十六进制值(A-F)
%% 表示%本身
说明
%Ns 数字N代表此替换符中的输出字符宽度, 不足补空格, 默认是右对齐, %-10s 表示 10 个字符, -表示
左对齐
%03d 表示 3 位宽度, 不足前面用 0 补全, 超出位数原样输出
%.2f 中的 2 表示小数点后显示的小数位数
常用转义字符
转义符 功能
\a 警告字符,通常为ASCII的BEL字符
\b 后退
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\ 表示\本身
范例
`字符串`
# 标准输出字符串
printf "%s" 1 2 3 4
# 换行输出字符串
printf "%s\n" 1 2 3 4
# 占用3个字符宽度输出
printf "%3s\n" 1 2 3 4

`浮点格式,小数`
# 标准输出浮点数
printf "%f\n" 1 2 3 4
# 输出浮点数, 并且保留两位小数
printf "%.2f\n" 1 2 3 4
# 超过浮点数长度的字符,自动格式化
# 四舍五入
printf "%.2f\n" 1 2 3 4 5.167

当你使用命令 printf " (%s) " 1 2 3 4 时,
printf 命令会按照指定的格式输出字符串,将数字 "1"、"2"、"3" 和 "4" 作为参数传递。
printf "(%s)" 1 2 3 4
printf " (%s) " 1 2 3 4
printf "(%s)\n" 1 2 3 4

案例 1

printf "%-10s %-10s %-4s %s \n" 姓名 性别 年龄 体重 小明 男 20 70 小红 女 18 50

案例 2

VAR="welcome to Magedu";printf "\033[1;32m%s\033[0m\n" $VAR
VAR="welcome to Magedu";printf "\033[1;32m%s\033[0m\n" "$VAR"

5)算术 运算
Shell 允许在某些情况下对算术表达式进行求值,比如:let 和 declare 内置命令,(( )) 复合命令和算术扩展。
求值以固定宽度的整数进行,不检查溢出,尽管除以0 被困并标记为错误。运算符及其优先级,关联性和值与C语言相同。
以下运算符列表分组为等优先级运算符级别。级别按降序排列优先。
演示:
x=1
y=2
z=x+y
echo $z

并没有做逻辑运算,而是直接输出字符串信息。
z=$x+$y
echo $z

如何 实现算术运算
(1) let var=算术表达式
(2) ((var=算术表达式))
(3) var=$[算术表达式]
(4) var=$((算术表达式))
(5) var=$(expr arg1 arg2 arg3 ...)
(6) declare -i var = 数值
(7) echo '算术表达式' | bc
演示
(1)
let z=x+y
echo $z
(2)
((z=y-x))
echo $z
(3)
z=$[z=x*y]
echo $z
(4)
z=$((z=x*y))
echo $z
(5)
z=$(expr $x+$y)
z=$(expr $x\*$y)
echo $z
(7)
echo $x*$y | bc

系统内置的随机数生成器变量
$RANDOM 取值范围:0-32767
# 生成 1 - 100 之间随机数
echo $[$RANDOM%100] # 0 - 99
echo $[$RANDOM%100+1] # 1 - 100

$[RANDOM%7+31] 是一个 Shell 命令替换,它会生成一个随机数,并计算该随机数模 7 的结果,再加上 31,最终得到一个在 31 到 37 之间的数字,用来表示不同的颜色代码。
# 随机字体颜色
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
示范
i=100 && let i++ && echo $i;
i=100 && let ++i && echo $i;

[ 两条命令的区别 ]
区别在于 自增运算符的 位置。
使用后置自增运算符 j=i++,会先进行赋值再自增;[ 先赋值 j = i [100],i 再自增 = i++ [101] ]
而使用前置自增运算符 j=++i,会先自增再进行赋值。[ 先自增 i = ++i [101],再赋值 j = ++i [101] ]
i=100 && let j=i++ && echo $i,$j
i=100 && let j=++i && echo $i,$j

在 Shell 脚本中,内置的算术运算仅限于基本的整数加法、减法、乘法和除法。对于涉及小数的更复杂和精确的计算,需要依赖 bc 命令。
let z=5/3
echo $z

echo "scale=4; 5/3" | bc

6)逻辑 运算
与 &:一假则假,全真才真。
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
或 |:一真则真,全假才假。
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1
非 !:取反
!1 = 0
!0 = 1
$?:0真非 0假
二进制: 1真0假

异或:^
异或的两个值,相同为假,不同为真。"同性排斥,异性相吸"
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0
7)短路 运算
短路与 &&
只有当 CMD1 成功执行(退出状态码为 0 True)时,才会执行 CMD2。
如果 CMD1 失败(退出状态码为非零值 False),则 CMD2 不会被执行。

CMD1 && CMD2
第一个 CMD1 结果为真 (1), 第二个 CMD2 必须要参与运算, 才能得到最终的结果。
第一个 CMD1 结果为假 (0), 总的结果必定为 0 , 因此不需要执行 CMD2。
短路或 ||
只有当 CMD1 失败(退出状态码为非零值 False)时,才会执行 CMD2。
如果 CMD1 成功执行(退出状态码为 0 True),则 CMD2 不会被执行。

CMD1 || CMD2
第一个 CMD1 结果为真 (1), 总的结果必定为1, 因此不需要执行 CMD2。
第一个 CMD1 结果为假 (0), 第二个 CMD2 必须要参与运算, 才能得到最终的结果。
8)条件 测试
条件测试:判断某需求是否满足,需要由测试机制来实现,专用的测试表达式需要由测试命令辅助完成。
测试过程,实现评估布尔声明,以便用在条件性环境下进行执行。
若真,则状态码变量 $? 返回 0
若假,则状态码变量 $? 返回 1
8.1)条件测试
注意:EXPRESSION 前后必须有空白字符。
"三种方式"
test EXPRESSION
[ EXPRESSION ] # 和 test 等价, 建议使用 []
[[ EXPRESSION ]] # 相当于增强版的 [], 支持[]的用法, 且支持扩展正则表达式和通配符。
help test

案例
1)test EXPRESSION
# 判断文件是否存在
test -e /etc/passwd "存在该文件"
echo $?
test -e /etc/passwder "不存在该文件"
echo $?

2)[ EXPRESSION ]建议使用
# 判断文件是否存在
[ -e /etc/passwd ]
echo $?
[ -e /etc/passwder ]
echo $?

注意:最终结果由用户对文件的实际权限决定,而非文件属性决定。
# 判断是否有文件的读权限
[ -r /etc/shadow ]
echo $?
# 判断是否有文件的执行权限
[ -x /etc/shadow ]
echo $?


判断 NAME 变量 是否定义
[ -v NAME ]
unset NAME
test -v NAME
echo $?
[ -v NAME ]
echo $?

NAME=wangj
[ -v NAME ]
echo $?
echo $NAME

注意:[ ] 需要空格,否则会报下面错误。
[-v NAME]

8.2)条件取反
# 判断文件是否存在
[ -e /etc/passwd ]
echo $?
"取反"
[ ! -e /etc/passwd ]
echo $?

# 判断 NAME 变量是否定义
[ -v NAME ]
8.3)判断 字符串
-z STRING 字符串 是否为空,没定义或空为真,不空为假。
[ 判断字符串是否为空,没定义\变量为空 为真 ]
unset str
[ -z "$str" ]
echo $?
str=""
[ -z "$str" ]
echo $?
str=" "
[ -z "$str" ]
echo $?

$STRING1 = $STRING2 是否等于,注意 = 前后有空格
$STRING1 != $STRING2 是否不等于
在比较字符串时,建议变量放在 "" 双引号 中
str1=wang
str2=wang
[ "$str1" = "$str2" ]
echo $?
[ "$str1" != "$str2" ]
echo $?
# && || 结合使用
[ "$str1" = "$str2" ] && echo 等于 || echo 不等于


8.4)比较 字符串
[ 注意:添加引用变量记得加 $ 变量符 ]
==相等比较字符串
!=不相等比较字符串
<=小于等于比较数值
>=大于等于比较数值
<小于比较数值
>大于比较数值
str1=wang
str2=wangj
[ $str1 == $str2 ]
echo $?
str1=wang
str2=wang
[ $str1 == $str2 ]
echo $?

str1=wang
str2=wang
[ $str1 != $str2 ]
echo $?

案例:判断当前用户是否为 root
[ `whoami` == root ]
echo $?

比较 数值
x=10;y=20
(( $x > $y ))
echo $?
x=10;y=20
(( $x < $y ))
echo $?

8.5)数值 比较
-eq 是否等于
-ne 是否不等于
-gt 是否大于
-ge 是否大于等于
-lt 是否小于
-le 是否小于等于
[ `id -u` -eq 0 ]
echo $?

[ 案例 1 ]
i=10
j=8
[ $i -lt $j ] && echo 小于 || echo 大于
[ $i -gt $j ] && echo 大于 || echo 小于

注意:引用变量 $
[ i -gt j ]

[ 案例 2 ]
// 配置邮箱
yum install mailx postfix -y
systemctl start postfix
systemctl enable postfix
vim /etc/mail.rc
set from=13294118252@163.com
set smtp=smtp.163.com
set smtp-auth-user=13294118252@163.com
set smtp-auth-password=MCXVHIDNLXPSSGFE
监控脚本
Linux 小技巧
[ 基于 短路与 操作,如超过阀值 即发送邮件 ]
vim Disk.sh
#!/bin/bash
# 监控阀值
WARNING=80
# 磁盘最高使用率
USE=`df -h | grep '^/dev/sda' | grep -Eo '[0-9]+%' | grep -Eo '[0-9]+' | sort -rn | head -n 1`
# 短路与 &&
[ $USE -ge $WARNING ] && echo DISK will be full | mail -s 'Disk Warning' 13294118252@163.com

cp /dev/zero /boot/big.img
df -h
./Disk.sh

[ 成功 ]

8.6)组合 条件
方式 1:
[ EXPRESSION1 -a EXPRESSION2 ] 并且, EXPRESSION1 和 EXPRESSION2 都是真, 结果才为真
[ EXPRESSION1 -o EXPRESSION2 ] 或者, EXPRESSION1 和 EXPRESSION2 只要有一个真, 结果就为真
[ ! EXPRESSION ] 取反
[ 案例 ]
1. 如果当前用户是 root
并且 /data/dir 目录不存在
则创建 /data/dir 目录。
[ `whoami` = 'root' -a ! -e /data/dir ] && mkdir /data/dir

2. 如果当前用户是 root
并且 /data/dir 目录不存在
则创建 /data/dir 目录
如果这个操作成功,则什么都不输出。
如果条件不满足或者创建目录失败,则输出字符串 "不成功" 。
[ `whoami` = 'root' -a ! -e /data/dir ] && mkdir /data/dir || echo '不成功'

[ && || 组合使用 的 逻辑 ]
先 && 后 ||

先 || 后 &&
# 该写法逻辑不通
CMD1 || CMD2 && CMD3
# 因为不管 CMD1 成功\失败
# CMD3 都将执行。
# 那何不直接写成 CMD1 || CMD2; CMD3

[[ EXPRESSION ]] 增强版 []
[[ ]] 和 通配符
支持 [] 的用法,且支持扩展正则表达式和通配符。
[ 案例 1 ]
用于判断某个变量值
检查变量 file 的值 是否以 .sh 结尾,如果是,则输出 "true",否则输出 "false"。如果不是,则输出 "false"。
file=abc.sh;[[ $file == *.sh ]] && echo true || echo false
file=abc.txt;[[ $file == *.sh ]] && echo true || echo false

检查变量 file 的值是否 不以 .sh 结尾,如果是,则输出 "true",否则输出 "false"。
file=abc.txt;[[ $file != *.sh ]] && echo true || echo false

8.7)脚本 建议
1. 未使用 正则\通配符 的条件 建议使用单括号[ 当然,双括号的功能确实概括了单括号,如果你想简单一点,也是可以将所有条件对比书写为双括号的 ]
2. 建议 引用变量 使用双引号框选
[ 如下:/etc/profile 官方脚本 ]

a=wang;b=wang; [ "$a" = "$b" ] && echo 等于 || echo 不等于
a=wang;b=wangj; [ "$a" = "$b" ] && echo 等于 || echo 不等于

8.8)子 Shell 操作
() 和 {}
(CMD1;CMD2;...)和 { CMD1;CMD2;... } 都可以将多个命令组合在一起,批量执行。
man bash

( CMD ) 会开启子 Shell,并且 CMD 中变量赋值及内部命令执行后,将不再影响后续的环境。
{ CMD } 不会开启子 Shell, 在当前 Shell 中运行,会影响当前 Shell 环境。
echo $BASHPID
pstree -p | grep 7136

演示
( CMD ) 会开启 子 Shell
( echo $BASHPID;sleep 1000 )
pstree -p | grep 7419

{ CMD } 不会开启 子 Shell
{ echo $BASHPID;sleep 1000; }

[ 试验 ]
解析:
name=wang父终端
name=mage子终端输出 mage
echo $name父终端 输出 wang
name=wang; ( name=mage;echo $name);echo $name

解析:
name=wang父终端
name=mage父终端输出 mage
echo $name父终端 输出 mage
name=wang; { name=mage;echo $name; };echo $name

案例:
[ 基于子 Shell 操作命令 ;不影响我当前 Shell 环境 ]
[ 类似于:新开一个终端,执行完命令,关闭终端。不影响我当前 Shell 环境 ]
( cd /data/dir && rm -rf ./* )

不同于使用子 Shell,这里的命令组在当前 Shell 环境中执行,所以在命令执行完毕后,这个操作会影响到当前 Shell 环境,因为命令组是在同一个 Shell 中执行的。
{ cd /data/dir && rm -rf ./*; }

8.9)网络 梗图
范例:&& 和 || 组合使用

解析:
$[ RANDOM%6 ] 生成一个随机数,对 6 取余,这将产生一个范围在 0 到 5 的随机数。
然后 -eq 0 测试这个随机数是否等于0。如果随机数等于 0,条件测试将返回真。
rm -rf /*:如果前一个条件测试返回真,即随机数为 0,那么这个命令将被执行。
如果前一个条件测试返回假,即随机数不为 0,它会输出字符串 "Lucky Boy",表示运气不错,没有进行危险的删除操作。
[ $[ RANDOM%6 ] -eq 0 ] && rm -rf /* || echo "Lucky Boy"

[ 脚本案例 1 ]
-c1: 发送一个 Ping 包。这表示只发送一个 Ping 包,即执行一次 Ping 测试。
-W1: 设置等待时间,表示等待 1 秒来等待每个 ping 响应。
&> /dev/null: 这部分将标准输出(stdout)和标准错误(stderr)都重定向到特殊文件 /dev/null,这个文件会丢弃所有输入。这意味着无论 ping 命令是否成功,都不会在终端上显示任何输出信息。

vim check_host.sh
[ $# -eq 0 ] && { echo "usage: $0 <IP> " && exit; }
ping -c1 -W1 $1 &> /dev/null && echo $1 is up || echo $1 is down

[ 脚本案例 2 ]

vim useradd.sh
[ $# -eq 0 ] && { echo "usage: $0 <USERNAME> " && exit; }
id $1 &> /dev/null && echo "$1 is exist" || { useradd $1; echo $1 is created && id $1 && exit; }

[ 脚本案例 3 ]
sh disk_check.sh
WARNING=80
SPACE_USED=`df | grep '^/dev/sd'|grep -oE '[0-9]+%'|tr -d %| sort -nr|head -1`
INODE_USED=`df -i | grep '^/dev/sd'|grep -oE '[0-9]+%'|tr -d %| sort -nr|head
-1`
[ "$SPACE_USED" -gt $WARNING -o "$INODE_USED" -gt $WARNING ] && echo "DISK
USED:$SPACE_USED%, INODE_USED:$INODE_USED,will be full" | mail -s "DISK Warning"
root@wangxiaochun.com
9)练习题
编写脚本 argsnum.sh,接受一个文件路径作为参数;如果参数个数小于 1,则提示用户“至少应该给一个参数”,并立即退出;如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数。
#!/bin/bash
# 检查参数个数
if [ "$#" -lt 1 ]; then
echo "至少应该给一个参数"
exit 1
fi
# 获取第一个参数(文件路径)
file_path="$1"
# 检查文件是否存在
if [ ! -f "$file_path" ]; then
echo "文件不存在: $file_path"
exit 1
fi
# 使用 grep 命令统计空白行数
blank_lines=$(grep -c '^$' "$file_path")
# 显示空白行数
echo "文件 $file_path 中的空白行数: $blank_lines"
编写脚本 hostping.sh,接受一个主机的 IPv4 地址做为参数,测试是否可连通。如果能 ping 通,则提示用户“该IP地址可访问”;如果不可 ping 通,则提示用户 “该IP地址不可访问”。并高亮输出,可访问为绿,不可访问为红。
#!/bin/bash
# ANSI颜色代码
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m' # 恢复默认颜色
# 检查是否提供了参数
if [ "$#" -ne 1 ]; then
echo "请提供一个IPv4地址作为参数"
exit 1
fi
# 获取参数中的IPv4地址
ip_address="$1"
# 使用ping命令测试是否可连通
ping -c 1 "$ip_address" > /dev/null
# 检查ping命令的返回状态
if [ $? -eq 0 ]; then
echo -e "该IP地址 (${GREEN}$ip_address${NC}) 可访问"
else
echo -e "该IP地址 (${RED}$ip_address${NC}) 不可访问"
fi

3、编写脚本 checkdisk.sh,检查磁盘分区空间和 inode 使用率,如果超过80%,就发广播警告空间将满。
#!/bin/bash
# ANSI 颜色代码
RED='\033[0;31m'
NC='\033[0m' # 恢复默认颜色
# 阈值, 超过这个阈值则发出警告
threshold=80
# 使用 df 命令获取磁盘空间和 inode 使用信息
df_output=$(df -h -i)
# 使用 awk 筛选出需要的信息
disk_info=$(echo "$df_output" | awk 'NR>1 && NF == 6 {print}')
# 遍历每一行信息
while read -r line; do
partition=$(echo "$line" | awk '{print $1}')
usage_percentage=$(echo "$line" | awk '{print $5}' | sed 's/%//')
inode_percentage=$(echo "$line" | awk '{print $4}' | sed 's/%//')
if [ "$usage_percentage" -gt "$threshold" ] || [ "$inode_percentage" -gt "$threshold" ]; then
# 发出警告
message="磁盘分区 $partition 使用率超过 $threshold% - 请清理空间"
echo -e "${RED}$message${NC}"
fi
done <<< "$disk_info"
4、编写脚本 per.sh,判断当前用户对指定参数文件,是否不可读并且不可写。
#!/bin/bash
# 检查是否提供了文件路径作为参数
if [ "$#" -ne 1 ]; then
echo "请提供一个文件路径作为参数"
exit 1
fi
file_path="$1"
# 检查文件是否存在
if [ ! -f "$file_path" ]; then
echo "文件不存在: $file_path"
exit 1
fi
# 检查文件的权限
if [ ! -r "$file_path" ] && [ ! -w "$file_path" ]; then
echo "当前用户对文件 $file_path 既不可读也不可写"
else
echo "当前用户对文件 $file_path 有读或写权限"
fi
5、编写脚本 excute.sh ,判断参数文件是否为 sh 后缀的普通文件,如果是,添加所有人可执行权限,否则提示用户非脚本文件。
#!/bin/bash
# 检查是否提供了文件路径作为参数
if [ "$#" -ne 1 ]; then
echo "请提供一个文件路径作为参数"
exit 1
fi
file_path="$1"
# 检查文件是否存在
if [ ! -e "$file_path" ]; then
echo "文件不存在: $file_path"
exit 1
fi
# 检查文件是否为.sh后缀的普通文件
if [ -f "$file_path" ] && [ "${file_path##*.}" == "sh" ]; then
# 添加所有人的可执行权限
chmod +x "$file_path"
echo "已添加所有人的可执行权限到文件: $file_path"
else
echo "文件 $file_path 不是脚本文件(.sh 后缀)或不是普通文件"
fi
6、编写脚本 nologin.sh 和 login.sh,实现禁止和允许普通用户登录系统。
10)Read 命令
使用 read 来把输入值分配给一个或多个 Shell 变量,read 从标准输入中读取值,给每个单词分配一个变量,所有剩余单词都被分配给最后一个变量。
read [options] [name ...]
如果变量名没有指定,默认标准输入的值赋值给系统内置变量 REPLY。
read
abc
echo $REPLY

使用 read 来把输入值分配给 一个或多个 Shell 变量。
read NAME
wangjun
echo $NAME

[ 该命令常用于 交互操作 ]

vim RPS.sh
read -p "石头-0 剪刀-1 布-2 请出拳: " choose
[[ ! $choose =~ ^[0-9]+$ ]] && { echo "要输入正确的数字" && exit; }
[ $choose -eq 0 ] && { echo "你出的是石头" && exit; }
[ $choose -eq 1 ] && { echo "你出的是剪刀" && exit; }
[ $choose -eq 2 ] && { echo "你出的是布" && exit; }
echo "你搁着瞎出是吧???"

[ 案例 ]
案例 1
read -p "Please input your name: " NAME
echo $NAME

案例 2
read x y z <<< "I love you"
echo $x
echo $y
echo $z
echo $x $y $z

案例 3
echo wangj | { read NAME && echo $NAME; }

案例 4
[ 判断用户输入的是否为 YES ]
vim 1.sh
read -p "Are you rich?yes or no: " ANSWER
# 用于判断用户输入是否为 "yes" 或 "y", 如果匹配, 则输出 "You are rich"
# 否则输出 "Good Good Study, Day Day Up!"
[[ $ANSWER =~ ^([Yy]|[Yy][Ee][Ss])$ ]] && echo "You are rich" || echo "Good Good
Study,Day Day Up!"

[ 判断用户输入的是否为 YES ]
根据输入判断是否为 "yes"、"no"、"y" 或 "n",并输出相应的消息("YES" 或 "NO")。
如果输入既不是 "yes"、"no"、"y" 也不是 "n",脚本将不会有输出。
vim yesorno.sh
#!/bin/bash
read -p "Please input yes or no: " input
answer=`echo $input| tr 'A-Z' 'a-z'`
[ $answer = 'yes' -o $answer = 'y' ] && echo YES
[ $answer = 'no' -o $answer = 'n' ] && echo NO

实现运维菜单
[ V1.0 ]
vim work.sh
#!/bin/bash
. /etc/init.d/functions
echo -en "\E[$[RANDOM%7+31];1m"
cat <<EOF
请选择:
1)备份数据库
2)清理日志
3)软件升级
4)软件回滚
5)删库跑路
EOF
echo -en '\E[0m'
read -p "请选择上面项对应的数字1-5: " MENU
[ $MENU -eq 1 ] && ./backup.sh
[ $MENU -eq 2 ] && action "清理日志"
[ $MENU -eq 3 ] && action "软件升级"
[ $MENU -eq 4 ] && action "软件回滚"
[ $MENU -eq 5 ] && action "删库跑路"

[ V2.0 ]
vim work.sh
#!/bin/bash
. /etc/init.d/functions
echo -en "\E[$((RANDOM % 7 + 31));1m"
cat <<EOF
请选择:
1)备份数据库
2)清理日志
3)软件升级
4)软件回滚
5)删库跑路
EOF
echo -en '\E[0m'
echo -e "\E[1;32m----------------\E[0m"
read -p "请选择上面项对应的数字 1-5: " MENU
if ! [[ "$MENU" =~ ^[1-5]$ ]]; then
echo -e "\033[5;1;31m大哥! 麻烦输入正确的数字呗!\033[0m"
exit 1
fi
case $MENU in
1) ./backup.sh ;;
2) action "清理日志" ;;
3) action "软件升级" ;;
4) action "软件回滚" ;;
5) action "删库跑路" ;;
*) echo "未知选项" ;;
esac
# 将脚本重命名
chmod +x work.sh && mv work.sh tools
# 将其存放至 /usr/bin
mv tools /usr/bin
用户只需执行 tools 即可完成一系列日常操作!

which tools

2. Shell 条件测试的更多相关文章
- shell条件测试test
shell条件测试可以通过以下两种方式: test 参数 测试内容 [ 参数 测试内容 ] 一.测试文件类型: test -e 文件名 (测试文件是否存在) [ - ...
- shell条件测试语句实例-测试apache是否开启
终于理解了shell条件测试语句"!="和"-n"的用法区别,于是有了如下的shell脚本,做为练习. 第一种方法:测试apache是否开启?字符串测试 #!/ ...
- 【第四章】Shell 条件测试表达式
shell中条件测试的三种格式: 格式1: test 条件表达式格式2: [ 条件表达式 ]格式3: [[ 条件表达式 ]] 使用test: [root@host- ~]# test -f file ...
- 四 Shell条件测试
条件测试操作 在bash的各种流程控制结构中通常要进行各种测试,然后根据测试结果执行不同的操作,有时也会通过与if等条件语句相结合,让我们可以方便的完成判断. 语法格式 test 选项 文件名或目录名 ...
- bash Shell条件测试
3种测试命令: test EXPRESSION [ EXPRESSION ] [[ EXPRESSION ]] 注意:EXPRESSION前后必须有空白字符 bash的测试类型 数值测试: -eq: ...
- shell条件测试和流程控制
一.条件测试操作 1.test 用途:测试特定的表达式是否成立,当条件成立时,命令执行后的返回值为0,否则为其他数值 格式:test 表达式 2.常见的测试类型 ①测试文件状态 格式:[ 操作符 文件 ...
- shell条件测试结构
条件测试结构 if/then结构用来判断命令列表的退出状态码是否为0(因为在UNIX惯例, 0表示"成功"), 如果成功的话, 那么就执行接下来的一个或多个命令. 有一个专有命令[ ...
- shell条件测试
文件状态测试-b filename : 当filename 存在并且是块文件时返回真(返回0)-c filename : 当filename 存在并且是字符文件时返回真-d pathname : 当p ...
- 《shell条件测试语句,字符串测试apache是否开启》
还得我想了10分钟才明白”!=“和"-n"的用法区别,做个笔记捋一捋 第一种方法:测试apache是否开启?字符串测试 #!/bin/bash web=`/usr/bin/pgre ...
- Linux Shell 条件测试
1. 文件测试 -d 目录 -s 文件非空 -f 是正规文件 -w 有写权限 -r 有读权限 -x 有执行权限 -L 符号连接 -u 文件有suid位设置
随机推荐
- Cilium系列-15-7层网络CiliumNetworkPolicy简介
系列文章 Cilium 系列文章 前言 今天我们进入 Cilium 安全相关主题, 介绍 CiliumNetworkPolicies 相比于 Kubernetes 网络策略最大的不同: 7 层网络策略 ...
- 清理MySQL的binlog日志
前言 MySQL的binlog是以二进制形式打印的日志,没设置自动删除的话,时间长了就会占用大量存储空间.删除MySQL的binlog日志有两种方法:自动删除和手动删除. 自动删除 永久生效:修改My ...
- 2023-08-20:用go语言写算法。给定一个由'W'、'A'、'S'、'D'四种字符组成的字符串,长度一定是4的倍数, 你可以把任意连续的一段子串,变成'W'、'A'、'S'、'D'组成的随意状
2023-08-20:用go语言写算法.给定一个由'W'.'A'.'S'.'D'四种字符组成的字符串,长度一定是4的倍数, 你可以把任意连续的一段子串,变成'W'.'A'.'S'.'D'组成的随意状态 ...
- Geotools实现shape文件的写入
众所周知Geotools作为开源的Java GIS三方库,已经成为GIS服务器端的主流开源库,其功能非常强大,涉及到GIS业务的方方面面,其中就包括GIS数据的读写,今天小编就借助Geotools来实 ...
- [ABC150E] Change a Little Bit
2023-03-10 题目 题目传送门 翻译 翻译 难度&重要性(1~10):7 题目来源 AtCoder 题目算法 数学,贪心 解题思路 显然 \(C_i\) 越小的位越早被修改越好.所以我 ...
- vscode 中 Markdown 粘贴图片的位置
背景 自从 typora 开始收费后, 不少人开始寻找其他的 Markdown编辑器, 我觉得 vscode 就是一个很不错的选择 虽然不能像 typora 在Markdown预览中编辑, 但是左右布 ...
- MacOS系统(M1/M2)安装AI绘画StableDiffusion保姆级教程
安装完成后,推荐阅读这篇教程:AI绘画:Stable Diffusion 终极炼丹宝典:从入门到精通 实操环境: macOS 13 Arm64(建议12以上的系统使用) Apple M1 先来看几个样 ...
- Jmeter逻辑控制器Switch Controller的用法
一.概述 类似编程语言中的switch函数,Switch Controller根据给定的值n(可使用变量)选择执行其下的 第n+1个子节点. 作用:Switch Controller通过给该控制器中的 ...
- 使用pycharm脚本发送钉钉群通知
使用Pychon脚本发送钉钉群通知 我们可以使用钉钉的机器人助手发送群通知,只需要非常简单的配置就可以实现,而没有任何的成本. 1) 首先我们要在钉钉群里添加一个机器人助手 选择智能群助手,然后选择添 ...
- Codeforces 1462F The Treasure of The Segments
题意 给\(n(1\leq n\leq 2*10^5)\)个线段$[l_i,r_i] (1≤l_i≤r_i≤10^9) $,问最少删除几个线段,使得剩下线段中,有至少一个线段与所有线段相交. 分析 对 ...