Shell学习
概述
定义
shell脚本就是将完成一个任务的所有命令按照执行的先后顺序,自伤而下写入到一个文件中,然后给予执行权限
- 给予执行文件授权
chmod 700 test.sh# 最好不用设置777,777十分危险
语法规范
-
名字要有意义
-
建议你使用.sh结尾
-
shell开头必须指明脚本运行的环境
# 指明解释器 #! /bin/bash #描述写清楚 #Author: #Created: #Release: #Script description: # 脚本组成 # 1. 解释环境 ##或者使用python的环境 #!/usr/bin/env python # 2. 注释说明 # 3. 执行代码
-
运行脚本
-
给予权限
chmod 700 test.sh# 最好不用设置777,777十分危险
-
解释器直接运行,不需要给予权限
bash test.sh
-
-
特殊符号
!! 执行上一次命令 $ 变量中取值 * 匹配所有 '' 单引号不解释变量 $? 判断上一条命令是否执行返回为真就是0,假为1,不成功为2 ` ` 里面放入命令,表示先执行其中的命令
-
数学运算
[root@iZ2zedjlje7b8m5cqfq666Z ~]# expr 1 + 2 3 [root@iZ2zedjlje7b8m5cqfq666Z ~]# expr 1 - 2 -1 [root@iZ2zedjlje7b8m5cqfq666Z ~]# expr 3 \* 2 6 [root@iZ2zedjlje7b8m5cqfq666Z ~]# expr 10 / 5 2 [root@iZ2zedjlje7b8m5cqfq666Z ~]# expr 10 % 3 1 [root@iZ2zedjlje7b8m5cqfq666Z ~]# expr 10 /5 expr: syntax error: unexpected argument “/5” [root@iZ2zedjlje7b8m5cqfq666Z ~]# echo $? 2 [root@iZ2zedjlje7b8m5cqfq666Z ~]# echo 10 % 3; echo $? 10 % 3 0 ## 双括号加$还能做运算 [root@iZ2zedjlje7b8m5cqfq666Z ~]# echo $((100%7)) 2
语法
格式化输出
一个程序需要有0个或者以上的输入,一个或者更多的输出
echo命令
[root@iZ2zedjlje7b8m5cqfq666Z ~]# echo "hhhhh"
hhhhh
[root@iZ2zedjlje7b8m5cqfq666Z ~]# echo -n "hhhhhh"
hhhhhh[root@iZ2zedjlje7b8m5cqfq666Z ~]#
[root@iZ2zedjlje7b8m5cqfq666Z ~]# echo -n "date is "; date
date is 2021年 08月 20日 星期五 16:53:25 CST
#!/usr/bin/bash
# 简易倒计时
for time in `seq 9 -1 0`; do
echo -n -e "\b$time"##-e代表转义字符,-n表示不换行
sleep 1
done
echo
程序交互
######test.sh
#!/usr/bin/bash
# 登陆注册案例
echo -n "Login: " #-n表示不换行
read acc
echo -n "Passwd: "
read -s -t50 -n6 -pnull pw #-s表示不显示密码,-t50表示50s内不输入自动跳过,-n6表示最多输入6位数,-pnull表示默认是null
echo
echo "你输入的账号是: $acc 密码是:$pw"
######结果
[root@iZ2zedjlje7b8m5cqfq666Z ~]# ./test.sh
Login: 1234
Passwd: null
你输入的账号是: 1234 密码是:123423
你还可以使用
read -p "Login: " acc
代替:
echo -n "Login: " #-n表示不换行
read acc
两个命令等价
变量
-
变量格式
变量名=值
-
变量使用
NAME="zhangsan" unset NAME # 取消变量 export NAME # 设置全局变量
数组
特性
#!/usr/bin/bash
# 数组案例
ARRAY=('a' 'b' 'c' 'd' 'e')
echo ${ARRAY[3]}
ARRAY[3]='D'
echo ${ARRAY[3]}
echo ${ARRAY[@]} # 打印数组中所有的元素
echo ${#ARRAY[@]} # 打印数组中元素的个数
echo ${!ARRAY[@]} # 打印数组中元素的索引
echo ${ARRAY[@]:2} #从索引2开始,打印数组
echo ${ARRAY[@]:1:2} #从索引1开始,访问两个元素
输出结果
d
D
a b c D e
5
0 1 2 3 4
c D e
b c
关联数组
#声明关联数组
declare -A array1
declare -A array2
array1[name]='zhangsan'
array1[age]=19
echo ${array1[name]}
array2=([name]='lisi' [age]=20)
echo ${array2[name]}
输出结果
zhangsan
lisi
数据比较运算
数学比较运算
符号 | 全称 |
---|---|
-eq | equal |
-ge | greater than or equal |
-gt | great than |
-le | less than or equal |
-lt | less than |
-ne | not equal |
文件比较运算
符号 | 解释 |
---|---|
-d | document ,判断目录是否存在 |
-f | file,判断文件是否存在 |
-e | 判断文件或者目录是否存在 |
-r|-w|-x | 判断文件存在且是否可读|可写|可执行 |
-s | 判断文件中存在是否为空(不为空是true) |
-O | 检查文件存在且是否被拥有 |
-G | 检查文件存在且是否被当前组拥有 |
这其中全在test命令中,可以用man test
命令查看
字符串比较运算
符号 | 解释 |
---|---|
== | 判断是否等于 |
!= | 判断是否不等于 |
-n | 判断字符串的长度是否大于0 |
-z | 检查字符串长度是否为0 |
if语句
#if语句
#没有/tmp/abc目录就创建
if [ ! -d /tmp/abc ]
then
mkdir -v /tmp/abc # -v表示显示创建信息
echo "successfully created /tmp/abc"
else
echo "/tmp/abc already exist"
fi
输出结果:
[root@iZ2zedjlje7b8m5cqfq666Z ~]# ./test.sh
mkdir: 已创建目录 '/tmp/abc'
successfully created /tmp/abc
[root@iZ2zedjlje7b8m5cqfq666Z ~]# ./test.sh
/tmp/abc already exist
if高级运用
#if语句
# if语句高级运用
if (( 100%3+6>9 )) #if双括号直接加入数学表达式
then
echo "yes"
else
echo "no"
fi
for i in r1 r2 r3 aaa bbb ccc r4
do
if [[ $i == r* ]] #用双中括号判断字符串是否匹配此为以r开头的字符
then
echo $i
fi
done
输出结果
[root@iZ2zedjlje7b8m5cqfq666Z ~]# ./test.sh
no
r1
r2
r3
r4
还可以使用elif
来控制判断条件
for语句
seq是数数命令 seq n k m ,从n开始,每次加k,一直到m,k可以省略,默认是1
两种写法:
# for语句两种写法
echo "第一种写法"
for i in Hava a nice day
do
echo -n "$i "
done
echo -e "\n第二种写法"
for (( i=0;i<10;i++ ))
do
echo -n "$i "
done
echo
执行结果:
第一种写法
Hava a nice day
第二种写法
0 1 2 3 4 5 6 7 8 9
还可以使用break
和continue
来控制循环
break高级用法
for (( ; ; )); do
echo "这是最外层循环"
for (( ; ; )); do
echo "这是中层循环"
for (( ; ; )); do
echo "这是里层循环"
break 1 # 跳出里层循环
break 2 # 跳出中层循环
break 3 # 跳出外层循环
done
done
done
输出结果:
### break 1
这是里层循环
这是中层循环
这是里层循环
这是中层循环
这是里层循环
这是中层循环
这是里层循环
这是中层循环
这是里层循环
.....
### break2
这是最外层循环
这是中层循环
这是里层循环
这是最外层循环
这是中层循环
这是里层循环
这是最外层循环
这是中层循环
这是里层循环
这是最外层循环
这是中层循环
这是里层循环
这是最外层循环
....
### break 3
这是最外层循环
这是中层循环
这是里层循环
while循环
# while循环语句制造99乘法表
n=1
while [ $n -lt 10 ]; do
for ((i = 1; i <= n; i++)); do
echo -n "$i * $n = $((i * n)) "
done
echo
n=$((n + 1))
done
# 使用while遍历文件内容
j=1
while read i; do
echo "第$j 行: $i"
j=$((j + 1))
done <$1
# 使用while读出文件中的列,IFS指定默认的列分隔符
IFS=$":" # 指定冒号分隔符
while read f1 f2 f3 f4 f5 f6 f7; do
echo "$f1 $f2 $f3"
done < /etc/passwd
输出结果
#结果一
[root@iZ2zedjlje7b8m5cqfq666Z ~]# ./test.sh
1 * 1 = 1
1 * 2 = 2 2 * 2 = 4
1 * 3 = 3 2 * 3 = 6 3 * 3 = 9
1 * 4 = 4 2 * 4 = 8 3 * 4 = 12 4 * 4 = 16
1 * 5 = 5 2 * 5 = 10 3 * 5 = 15 4 * 5 = 20 5 * 5 = 25
1 * 6 = 6 2 * 6 = 12 3 * 6 = 18 4 * 6 = 24 5 * 6 = 30 6 * 6 = 36
1 * 7 = 7 2 * 7 = 14 3 * 7 = 21 4 * 7 = 28 5 * 7 = 35 6 * 7 = 42 7 * 7 = 49
1 * 8 = 8 2 * 8 = 16 3 * 8 = 24 4 * 8 = 32 5 * 8 = 40 6 * 8 = 48 7 * 8 = 56 8 * 8 = 64
1 * 9 = 9 2 * 9 = 18 3 * 9 = 27 4 * 9 = 36 5 * 9 = 45 6 * 9 = 54 7 * 9 = 63 8 * 9 = 72 9 * 9 = 81
#结果二
[root@iZ2zedjlje7b8m5cqfq666Z ~]# ./test.sh /etc/passwd
第1 行: root:x:0:0:root:/root:/bin/bash
第2 行: bin:x:1:1:bin:/bin:/sbin/nologin
第3 行: daemon:x:2:2:daemon:/sbin:/sbin/nologin
第4 行: adm:x:3:4:adm:/var/adm:/sbin/nologin
第5 行: lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
第6 行: sync:x:5:0:sync:/sbin:/bin/sync
第7 行: shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
第8 行: halt:x:7:0:halt:/sbin:/sbin/halt
第9 行: mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
第10 行: operator:x:11:0:operator:/root:/sbin/nologin
第11 行: games:x:12:100:games:/usr/games:/sbin/nologin
第12 行: ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
....
#结果三
[root@iZ2zedjlje7b8m5cqfq666Z ~]# ./test.sh
root x 0
bin x 1
daemon x 2
adm x 3
lp x 4
sync x 5
shutdown x 6
halt x 7
mail x 8
operator x 11
games x 12
ftp x 14
nobody x 65534
dbus x 81
systemd-coredump x 999
systemd-resolve x 193
tss x 59
polkitd x 998
unbound x 997
libstoragemgmt x 996
cockpit-ws x 995
setroubleshoot x 994
sssd x 993
insights x 992
until语句
和while相反,条件为假开始循环
i=1
until [ $i -gt 10 ]; do
echo "$i"
i=$((i+1))
done
#输出结果
1
2
3
4
5
6
7
8
9
10
case
while :; do
read -p "请输入数字:" i
case $i in
1 | 2 | 3)
echo "你选择了一个小于4的数"
;;
4 | 5 | 6)
echo "你选择了一个4-6之间的数"
;;
7 | 8 | 9)
echo "你选择了一个大于7的数"
;;
*)
echo "你选择了一个很大的数,我要退出了"
exit 0
;;
esac
done
输出结果:
[root@iZ2zedjlje7b8m5cqfq666Z ~]# ./test.sh
请输入数字:1
你选择了一个小于4的数
请输入数字:2
你选择了一个小于4的数
请输入数字:5
你选择了一个4-6之间的数
请输入数字:4
你选择了一个4-6之间的数
请输入数字:6
你选择了一个4-6之间的数
请输入数字:8
你选择了一个大于7的数
请输入数字:9
你选择了一个大于7的数
请输入数字:10
你选择了一个很大的数,我要退出了
符号 | 解释 |
---|---|
$0 | 脚本名字 |
$* | 脚本参数 |
$# | 传参数量 |
$$ | 脚本执行进程号 |
$_ | 最后执行命令 |
$N | 第n个参数 |
函数
#函数两种方法的使用
#第一种定义方法
function start {
echo "Starting.... [ok]"
}
#第二种定义方法
stop() {
echo "Stopping.... [ok]"
}
#函数不会自己执行,除非你调用
start
start
stop
stop
输出结果:
Starting.... [ok]
Starting.... [ok]
Stopping.... [ok]
Stopping.... [ok]
Nginx启动管理脚本
sh -x
正则表达式
特殊字符
定位符使用技巧:同时锚定开头和结尾,做精确匹配;单一锚定开头和结尾,做到模糊匹配
定位符 | 说明 |
---|---|
^ | 锚定开头 ^a是以a开头 默认锚定一个字符 |
$ | 锚定结尾 $a是以a结尾 默认锚定一个字符 |
测试案例:
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^ac$" file
ac
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^a" file
a
abc
ac
abbbc
aaaaccc
abcdfs
assd
assskslss
askdsk
abbbbc
abbbc
asjhsjhsc
### egrep 和 grep -E 一样
匹配符
匹配符 | 说明 |
---|---|
. | 匹配除回车以外的任意字符 |
() | 字符串分组 |
[] | 定义字符类,匹配括号中的一个字符 |
[^] | 表示否定括号中出现的字符,取反 |
\ | 转义字符 |
| | 或 |
测试案例:
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^a.c$" file
abc
aic
agc
a2c
a_c
aZc
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^a[0-9]c$" file
a2c
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^a[^0-9]c$" file
abc
aic
agc
a_c
aZc
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^a[a-z]c$" file
abc
aic
agc
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^a[a-Z]c$" file
abc
aic
agc
aZc
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^a[^a-Z]c$" file
a2c
a_c
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^a\*c$" file
a*c
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^a*c$" file
ac
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^(a|b)c$" file
ac
bc
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^(a|b).c$" file
abc
bbc
aic
agc
a2c
a_c
aZc
bac
a*c
限定符
限定符 | 说明 |
---|---|
* | 表示该字符不出现或者多次出现 |
? | 表示该字符出现一次或者不出现 |
+ | 表示前面字符出现一次或者多次,但必须出现一次 |
{n,m} | 表示该字符最少n次,最多m次 |
{m} | 表示该字符正好出现了m次 |
测试案例:
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^ab*c$" file
abc
ac
abbbc
abbbbc
abbbc
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^ab?c$" file
abc
ac
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^ab+c$" file
abc
abbbc
abbbbc
abbbc
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^ab{3}c$" file
abbbc
abbbc
[root@iZ2zedjlje7b8m5cqfq666Z ~]# egrep "^ab{1,3}c$" file
abc
abbbc
abbbc
元字符
字符 | 说明 |
---|---|
[a-z] | 字符范围。匹配指定范围内的任意字符。例如,’[a-z]’ 可以匹配 ‘a’ 到 ‘z’ 范围内的任意小写字母字符。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。 |
\B | 匹配非单词边界。‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。 |
\d | 匹配一个数字字符。等价于 [0-9]。 |
\D | 匹配一个非数字字符。等价于 [ ^ 0-9]。 |
\w | 匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]’。 |
\W | 匹配任何非单词字符。等价于 ‘[ ^ A-Za-z0-9_]’。 |