重点:

条件测试。

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 条件测试的更多相关文章

  1. shell条件测试test

    shell条件测试可以通过以下两种方式: test   参数    测试内容 [ 参数  测试内容 ] 一.测试文件类型: test  -e   文件名          (测试文件是否存在) [ - ...

  2. shell条件测试语句实例-测试apache是否开启

    终于理解了shell条件测试语句"!="和"-n"的用法区别,于是有了如下的shell脚本,做为练习. 第一种方法:测试apache是否开启?字符串测试 #!/ ...

  3. 【第四章】Shell 条件测试表达式

    shell中条件测试的三种格式: 格式1: test 条件表达式格式2: [ 条件表达式 ]格式3: [[ 条件表达式 ]] 使用test: [root@host- ~]# test -f file ...

  4. 四 Shell条件测试

    条件测试操作 在bash的各种流程控制结构中通常要进行各种测试,然后根据测试结果执行不同的操作,有时也会通过与if等条件语句相结合,让我们可以方便的完成判断. 语法格式 test 选项 文件名或目录名 ...

  5. bash Shell条件测试

    3种测试命令: test EXPRESSION [ EXPRESSION ] [[ EXPRESSION ]]  注意:EXPRESSION前后必须有空白字符 bash的测试类型 数值测试: -eq: ...

  6. shell条件测试和流程控制

    一.条件测试操作 1.test 用途:测试特定的表达式是否成立,当条件成立时,命令执行后的返回值为0,否则为其他数值 格式:test 表达式 2.常见的测试类型 ①测试文件状态 格式:[ 操作符 文件 ...

  7. shell条件测试结构

    条件测试结构 if/then结构用来判断命令列表的退出状态码是否为0(因为在UNIX惯例, 0表示"成功"), 如果成功的话, 那么就执行接下来的一个或多个命令. 有一个专有命令[ ...

  8. shell条件测试

    文件状态测试-b filename : 当filename 存在并且是块文件时返回真(返回0)-c filename : 当filename 存在并且是字符文件时返回真-d pathname : 当p ...

  9. 《shell条件测试语句,字符串测试apache是否开启》

    还得我想了10分钟才明白”!=“和"-n"的用法区别,做个笔记捋一捋 第一种方法:测试apache是否开启?字符串测试 #!/bin/bash web=`/usr/bin/pgre ...

  10. Linux Shell 条件测试

    1. 文件测试 -d 目录 -s 文件非空 -f 是正规文件 -w 有写权限 -r 有读权限 -x 有执行权限 -L 符号连接 -u 文件有suid位设置

随机推荐

  1. Cilium系列-15-7层网络CiliumNetworkPolicy简介

    系列文章 Cilium 系列文章 前言 今天我们进入 Cilium 安全相关主题, 介绍 CiliumNetworkPolicies 相比于 Kubernetes 网络策略最大的不同: 7 层网络策略 ...

  2. 清理MySQL的binlog日志

    前言 MySQL的binlog是以二进制形式打印的日志,没设置自动删除的话,时间长了就会占用大量存储空间.删除MySQL的binlog日志有两种方法:自动删除和手动删除. 自动删除 永久生效:修改My ...

  3. 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'组成的随意状态 ...

  4. Geotools实现shape文件的写入

    众所周知Geotools作为开源的Java GIS三方库,已经成为GIS服务器端的主流开源库,其功能非常强大,涉及到GIS业务的方方面面,其中就包括GIS数据的读写,今天小编就借助Geotools来实 ...

  5. [ABC150E] Change a Little Bit

    2023-03-10 题目 题目传送门 翻译 翻译 难度&重要性(1~10):7 题目来源 AtCoder 题目算法 数学,贪心 解题思路 显然 \(C_i\) 越小的位越早被修改越好.所以我 ...

  6. vscode 中 Markdown 粘贴图片的位置

    背景 自从 typora 开始收费后, 不少人开始寻找其他的 Markdown编辑器, 我觉得 vscode 就是一个很不错的选择 虽然不能像 typora 在Markdown预览中编辑, 但是左右布 ...

  7. MacOS系统(M1/M2)安装AI绘画StableDiffusion保姆级教程

    安装完成后,推荐阅读这篇教程:AI绘画:Stable Diffusion 终极炼丹宝典:从入门到精通 实操环境: macOS 13 Arm64(建议12以上的系统使用) Apple M1 先来看几个样 ...

  8. Jmeter逻辑控制器Switch Controller的用法

    一.概述 类似编程语言中的switch函数,Switch Controller根据给定的值n(可使用变量)选择执行其下的 第n+1个子节点. 作用:Switch Controller通过给该控制器中的 ...

  9. 使用pycharm脚本发送钉钉群通知

    使用Pychon脚本发送钉钉群通知 我们可以使用钉钉的机器人助手发送群通知,只需要非常简单的配置就可以实现,而没有任何的成本. 1) 首先我们要在钉钉群里添加一个机器人助手 选择智能群助手,然后选择添 ...

  10. 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) $,问最少删除几个线段,使得剩下线段中,有至少一个线段与所有线段相交. 分析 对 ...