shell 编程语言脚本总结
一、简单了解shell语言脚本
1. 执行环境
sh bash等
shell 默认为 /bin/bash
2. 执行流程
输入指令 ------> shell解释 ------> 内核 ------> 结果还回shell ------> 用户
例:
打开音乐 --- shell --- 播放音乐 --- shell --- 二进制 --- 内核 --- 调度cpu、内存、网卡、硬盘、调度硬件 --- 声卡 --- 音乐播放器
3. 执行方法
命令 | 执行效果和要求 |
---|---|
sh 文件路径 | 只运行脚本中的代码 |
bash 文件路径 | 只运行脚本中的代码,选项 -x 表示详细运行时显示详细的步骤 |
source 文件路径 | 全量执行脚本中的代码,例:cd /root,脚本执行完成之后会进入/root目录 |
./文件名 | 只运行脚本中的代码,但是脚本需要执行权限,使用chmod命令进行赋权 |
二、重定向输入
1. 命令
echo 输入的内容 符号 目标文件
符号 | 作用 | 示例 |
---|---|---|
< 文件名 | 将文件中的内容输出 | 更改用户user1密码: passwd --stdin user1 < passwd.txt |
输入的内容 > 文件名 | 将输入的内容输入到目标文件(覆盖) | 这是test1文件 > test1.txt |
输入的内容 >> 文件名 | 将输入的内容输入到目标文件(追加) | 这是追加的内容 >> test1.txt |
&> 文件名 | 将错误信息和标准信息重定向到文件中(覆盖) | 将输出的冗余信息重定向到黑洞文件: yum mkcache &> /dev/null |
2> 文件名 | 将错误信息重定向到文件中(覆盖,2>> 追加) | yum mkcache &> /dev/null |
2. 实例
(1)将"123"重定向到passwd.txt文件
echo 123 > passwd.txt
(2)将"456"重定向追加到passwd.txt文件
echo 456 >> passwd.txt
(3)用"123123"将passwd文件内容覆盖
echo 123123 > passwd.txt
(4)将passwd.txt文件中的内容设置为用户user1的密码
systemctl stop firewalld.service
setenforce 0
passwd --stdin user1 < passwd.txt
(5)将 ls / 的输出结果重定向到黑洞文件/dev/null 和 test1.txt文件
ls / &> /dev/null
ls / &> test1.txt
三、变量
1. 基本概念
作用:
用于赋值、传参
使用:
打印和引用变量时变量 $ 符号,$a
定义:
不能使用命令和中文作为变量名
变量名不能用特殊字符字符开头
2. 变量类型
(1)基本变量
整数型:int
字符串:string
布尔:真 非0 假 0
(2)自定义变量
可以自己定义、修改、使用
a=1
b=2
echo $a $b
1 2
a=2
echo $a $b
2 2
(3)只读变量
不可以重新赋值,不可删除,重启消失
readnonly 变量名
a=1
readnoly a
(4)全局变量
所有用户自定义变量在子shell中也可以使用
临时:
export 变量名
b=1
export b
永久:
优点
① 全局范围
② 持久性
③ 共享性
副作用
① 如果相同的变量名,直接引用会导致不确定性
②在脚本中一般使用自定义变量
进入 /etc/profile 配置文件进行添加
export 变量名=值
echo "export b=1" >> /etc/porfile
source /etc/passwd
(5)位置变量
命令行参数,运行脚本程序时,传递它们的值,位置变量用于将外部数据传递给脚本执行
传参:从左到右
脚本名 参数1 参数2 参数3 ……
vim test1.sh
#!/bin/bash
sum=$[$1 + $2]
echo $sum
sh test1.sh 1 2
3
(6)预定义变量
变量名 | 作用 |
---|---|
$# | 显示传参个数 |
$? | 判断真假(0为真,1为假),判断上一行的命令是否执行成功(成功0,不成功非0) |
$* | 将出输内容分行处理(加引号" "表示不分行) |
$@ | 将输出内容分行处理(无论加不加引号" "都分行) |
$0 | 表示当前脚本或命令 |
$1 $2 $3 | 表示脚本或命令的参数 |
$HOME | 返回当前登录用户家目录 |
$PWD | 返回当前所在位置 |
$USER | 返回当前登录用户 |
$SHELL | 返回当前正在使用的shell程序路径 |
$PATH | 返回可执行文件所在目录 |
3. read 输入赋值
命令 | 作用 |
---|---|
read -p "提示符" 变量名 | 指定提示符,用于提示用户输入信息 |
read -a 变量名 | 将输入的内容存储到数组中(每个值之间用空格隔开),调用第一个值 ${变量名[0]},调用第二个值 $ |
(1)用read -p 写一个两个数任意相加求和的脚本
vim test2.sh
#!/bin/bash
# 两个数任意相加求和
read -p "请输入第一个数:" num1
read -p "请输入第二个数:" num2
sum=$(($num1+$num2))
echo "$num1 与 $num2 的和为 $sum"
sh test2.sh
请输入第一个数:1
请输入第二个数:2
1 与 2 的和为 3
(2)用read -a 写一个两个数任意相加求和的脚本
vim test3.sh
#!/bin/bash
# 两个任意的数相加求和
echo "请输入两个数字(用空格隔开):"
read -a num
sum=$[${num[0]}+${num[1]}]
echo "合为:$sum"
sh test3.sh
请输入两个数字(用空格隔开):
1 2
合为:3
四、运算
1. 运算法则
运算符(只支持整数) | 含义 |
---|---|
+ | 加 |
- | 减 |
\* | 乘 |
/ | 除 |
% | 取余 |
i++ | 先赋值再自增1 |
i-- | 先赋值再自减1 |
++i | 先自增1再赋值 |
--i | 先自减1再赋值 |
2. 整数运算
$(($a+$b))
$[$a+$b]
let c=$a+$b
vim test4.sh
#!/bin/bash
# 三种运算方法
a=1
b=2
# 第一种
c1=$(($a+$b))
echo "第一种合为:$c1"
# 第二种
c2=$[$a+$b]
echo "第二种合为:$c2"
# 第三种
let c3=$a+$b
echo "第三种合为:$c3"
sh test4.sh
第一种合为:3
第二种合为:3
第三种合为:3
五、环境变量
将有执行权限的脚本添加到环境变量,可以在任意目录下输入脚本名,即可运行脚本
命令 env 可以查看当前所有环境变量
将 /data/revise 目录下的脚本test4.sh添加到环境变量
ll test4.sh
-rw-r--r--. 1 root root 216 6月 5 22:29 test4.sh
chmod 777 test4.sh
ll test4.sh
-rwxrwxrwx. 1 root root 216 6月 5 22:29 test4.sh
pwd
/data/revise
echo "expot PATH=$PATH:/data/revise" ~/.bashrc
expot PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/data/revise/test4.sh:/data/revise/test4.sh:/data/revise/test4.sh:/data/revise/test4.sh:/data/revise:/data/revise /root/.bashrc
source ~/.bashrc
env | grep "test4.sh"
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/data/revise/test4.sh:/data/revise/test4.sh:/data/revise/test4.sh:/data/revise/test4.sh:/data/revise
test4.sh
第一种合为:3
第二种合为:3
第三种合为:3
六、条件判断
1. 测试命令
test [条件表达式]
条件表达式 | 作用 |
---|---|
-e | 测试目录是否存在 |
-d | 测试是否为目录 |
-f | 测试是否为文件 |
-r | 测试文件是否可读 |
-w | 测试文件是否可写 |
-x | 测试文件是否可执行 |
-z | 测试字符串是否为空 |
-n | 测试字符串是否存在 |
2. 比较符
字符(只支持整数) | 符号(既支持整数也支持较字符串) | 含义 |
---|---|---|
-eq | == | 等于 |
-ne | != | 不等于 |
-lt | < | 小于 |
-le | <= | 小于等于 |
-gt | > | 大于 |
-ge | >= | 大于等于 |
3. 逻辑运算符
[ 表达式1 ] 操作符 [ 表达式2 ]
[[ 表达式1 操作符 表达式2 ]]
字母操作符 | 符号操作符 | 含义 | 成立条件 |
---|---|---|---|
-a | && | 且 | 前后两个条件都要成立 |
-o | || | 或 | 前后两个条件只需成立一个 |
! | 非 | 前后两个条件都不成立 |
七、判断
1. if ... fi
如果……就……
格式
if [[ 条件表达式 ]]
then
条件成立执行语句
fi
aa=1
if [[ $aa -eq 1 ]]
> then
> echo "aa的值为1"
> fi
aa的值为1
2. if ... else ...fi
如果……就……否则……
格式
if [[ 条件表达式 ]]
then
条件成立执行语句
else
条件不成立执行语句
fi
aa=2
if [[ $aa == 1 ]]
> then
> echo "aa的值为1"
> else
> echo "aa的值不为1"
> fi
aa的值不为1
3. if ... elif ... else ... fi
如果……就……除此之外……就……否则……
格式
if [[ 条件1表达式 ]]
then
条件1成立执行语句
elif [[ 条件2表达式 ]]
then
条件2成立表达式
else
条件不成立执行语句
fi
aa=2
if [[ $aa -eq 1 ]]
> then
> echo "aa的值为1"
> elif [[ $aa == 2 ]]
> then
> echo "aa的值为2"
> else
> echo "aa的值即不为1也不为2"
> fi
aa的值为2
4. case
格式
case 变量(标签) in
变量值1)
变量值1成立执行语句
;;
变量值2)
变量值2成立执行语句
;;
变量值3)
变量值3成立执行语句
;;
*)
以上变量值未成立执行语句
esac
aa=3
case $aa in
> 1)
> echo "aa的值为1"
> ;;
> 2)
> echo "aa的值为2"
> ;;
> 3)
> echo "aa的值为3"
> ;;
> *)
> echo "aa的是不是1 2 3"
> esac
aa的值为3
5. 实例
(1) 检查用户家目录中的 test.sh 文件是否存在,并且检查是否有执行权限
[root@localhost data]# vim test1.sh
#!/bin/bash
# 检查用户家目录中的 test.sh 文件是否存在,并且检查是否有执行权限
test -f ~/test.sh
if [ $? == 0 ]
then
echo "家目录的test.sh存在"
test -x ~/test.sh
if [ $? == 0 ]
then
echo "并且拥有执行权限"
else
echo "无执行权限"
fi
else
echo "家目录中无test.sh文件"
fi
(2) 对成绩进行判断并分组
[root@localhost data]# vim test2.sh
#!/bin/bash
# 提示用户输入100米赛跑的秒数,要求判断秒数大于0且小于等于10秒的进入选拔赛,
# 大于10秒的都淘汰,如果输入其它字符则提示重新输入;
# 进入选拔赛的成员再进一步判断男女性别,
#男生进男生组,女生进女生组,如果输入错误请提示错误
read -p "请输入姓名:" name
read -p "请输入您的性别:" sex
if [ $sex == "男" ]
then
group="男生组"
elif [ $sex == "女" ]
then
group="女生组"
else
echo "输入错误,请重新输入!"
exit
fi
read -p "输入100米赛跑的成绩:" num
if [[ $num -gt 0 && $num -le 10 ]]
then
echo "恭喜$name 已成功进入选拔赛!"
echo "所在组为:$group"
elif [ $num > 10 ]
then
echo "很遗憾,$name 没有进入选拔赛!"
else
echo "输入错误,请重新输入!"
fi
(3)用case语句解压根据后缀名为 .tar.gz 或 .tar.bz2 的压缩包到 /opt 目录
[root@localhost data]# vim test3.sh
#!/bin/bash
# 用case语句解压根据后缀名为 .tar.gz 或 .tar.bz2 的压缩包到 /opt 目录
read -p "输入文件路径:" a
case $a in
*.tar.gz)
tar -zxf $a -C /opt
echo "$a 文件已成功解压到 /opt 目录下"
;;
*.tar.bz2)
tar -jxf $a -C /opt
echo "$a 文件已成功解压到 /opt 目录下"
;;
*)
echo "$a 文件不存在!"
esac
(4)判断是否为整数并判断奇偶性
[root@localhost data]# vim test4.sh
#!/bin/bash
# 提示用户输入内容,使用if 语句判断输入的内容是否为整数。
# 若是整数判断是奇数还是偶数。
read -p "输入一个数:" num
if [ $num -eq $num ] &> /dev/null
then
echo "$num 是一个整数"
let i=$num%2
if [ $i == 0 ]
then
echo "$num 是偶数"
else
echo "$num 是奇数"
fi
else
echo "$num 是不是整数"
fi
(5)用if 语句判断主机是否存活
[root@localhost data]# vim test6.sh
#!/bin/bash
# 用if 语句判断主机是否存活
read -p "输入需要测试的主机ip地址:" ip
ping -c 5 -w 5 $ip &> /dev/null
if [ $? -eq 0 ]
then
echo "主机 $ip 为存活状态"
else
echo "主机 $ip 为死亡状态"
fi
(6)管理防火墙
[root@localhost data]# vim test7.sh
echo "4.status"
read -p "请输入控制号:" num
case \$num in
1)
systemctl start firewalld.service
echo "firewalld 已成功开启!"
;;
2)
systemctl stop firewalld.service
echo "firewalld 已成功关闭!"
;;
3)
systemctl restart firewalld.service
echo "firewalld 已成功重启!"
;;
4)
systemctl status firewalld.service
echo "firewalld 状态已成功显示!"
;;
*)
echo "输入错误,请重新输入!"
esac
" > /etc/init.d/firewalld.sh
八、循环
1. for 循环
格式
(1)bash 格式
for 变量名 in {范围}
do
循环体(循环语句)
done
(2)类 C 格式
for ((变量赋值;变量范围控制;变量变化))
do
循环体(循环语句)
done
# bash 格式
for i in {1..5}
> do
> echo "i的值为:$i"
> done
i的值为:1
i的值为:2
i的值为:3
i的值为:4
i的值为:5
# 类C格式
for ((i=1;i<=5;i++))
> do
> echo "i的值为:$i"
> done
i的值为:1
i的值为:2
i的值为:3
i的值为:4
i的值为:5
2. whlie 循环
格式
while [[ 循环条件 ]]
do
循环条件成立执行语句
done
i=0
while [[ i -lt 5 ]]
> do
> i=$[$i+1]
> echo "这是第 $i 次循环"
> done
这是第 1 次循环
这是第 2 次循环
这是第 3 次循环
这是第 4 次循环
这是第 5 次循环
3. 死循环
(1)for 死循环
格式
for (;; )
do
循环体(循环语句)
done
(2)while 死循环
常用
格式
while true
do
循环体(循环语句)
done
4. 循环控制
(1)终止 break
满足条件运行break终止循环
用法
for 变量名 in {范围}
do
if [[ 结束循环条件 ]]
then
break
fi
循环体(循环语句)
done
# 当i=3是终止循环
for i in {1..5}
> do
> echo "i的值为:$i"
> if [[ $i -eq 3 ]]
> then
> break
> fi
> done
i的值为:1
i的值为:2
i的值为:3
(2)继续 continue
满足条件循行continue不执行(跳过)此次循环,继续下一次循环
用法
for 变量名 in {范围}
do
if [[ 结束循环条件 ]]
then
continue
fi
循环体(循环语句)
done
# 当i=3时跳过此次循环,继续执行下一次循环
for i in {1..5}
> do
> if [[ $i -eq 3 ]]
> then
> continue
> fi
> echo "i的值为:$i"
> done
i的值为:1
i的值为:2
i的值为:4
i的值为:5
5. 实例
(1)计算从1到100所有整数的和
(2)提示用户输入一个小于100的整数,并计算从1到该数之间所有整数的和
(3)求从1到100所有整数的偶数和、奇数和
(4) 用户名存放在users.txt文件中,每行一个,判断文件里的用户是否存在,若该用户存在,输出提示该用户已存在;用户存在但没设密码,则提示用户并让用户设置码;若该用户不存在,提示用户输入密码,建立用户并设立其密码
(5)检测指定范围主机是否通信,并将通信的主机ip输出到文件host_ip中
(6) 用户输入密码,脚本判断密码是否正确,正确密码为123456,输入正确提示正确信息,连续输错3次则报警
(7)使用循环语句将一个 0到255 之间的十进制数转换成8位数二进制数
……
……
……
九、函数
1. 定义函数
格式
函数名(){
函数体(函数要运行的语句)
}
2. 调用函数
格式
函数名 [参数1] [参数2] ……
vim test5.sh
#!/bin/bash
test(){
a=1
b=2
echo "$[$a+$b]"
}
test
sh test5.sh
3
# 函数传参
vim test5.sh
#!/bin/bash
test(){
echo "$[$1+$2]"
}
test 1 2
sh test5.sh
3
# 在另一个文件中调用函数
vim test6.sh
#!/bin/bash
. /test5.sh
test 1 2
3. 实例
① 函数能够接受一个参数,参数为用户名
判断一个用户是否存在 如果存在,就返回此用户的shell 和 UID
并返回正常状态值
如果不存在,就说此用户不存在;并返回错误状态值
② 在主程序中调用函数
十、数组
1. 介绍
作用:一次性定义多个变量,充当数据存储的库
类型:数值类型、字符类型
数值型
arr=(1 2 3)
字符型
arr=(a b c)
2. 定义数组
定义普通数组:(索引从0开始)
arr=()
declare -a arr
定义关联数组:(自定义索引)
declare -A arr
3. 定义索引
普通索引:
arr=(a b c d)
索引从0开始,0 1 2 3
自定义索引:
arr=([aa]=a [bb]=b [cc]=c [dd]=d)
索引为:aa bb cc dd
4. 引用数组
(1)获取数组的值
${arr[@]}
${arr[*]}
(2)获取数组的索引
${!arr[@]}
${!arr[*]}
(3)获取数组指定索引的值
${arr["索引"]}
(4)获取数组指定索引范围的值
获取数组arr索引为1-3的值
${arr[@]:1:3}
(5)索取数组长度
${#arr[@]}
${#arr[*]}
(6)临时更改数组的值
${arr[*]/被更改值/新值}
将数组arr中的a值改为aa
${arr[*]/a/aa}
(7)永久更改
arr["已有索引"]=新值
将数组arr索引为0的值改为a
arr[0]=a
(注:若数组中没有该索引,则会在此索引处创建一个该索引所对应的值)
arr=${arr[@]/a/aa}
(8)添加值
普通索引:
arr+=(a b c)
arr[${#arr[@]}]=(a b c)
自定义索引:
arr+=([aa]=a [bb]=b [cc]=c)
5、实例