shell脚本基础
一、变量
1、变量的定义方式
变量名=值
2、变量的2个类型
1、普通变量
-
存储用户相关的数据,用户的家目录,以及用户程序用到的登录信息
-
作用域不同,普通变量仅在当前的shell有效
2、环境变量
-
存储的系统核心数据,可执行文件的路径,系统的uid,系统的语言等
-
当前shell和子shell都有效
-
export 变量名=值
[root@server ~]# export qq=q1
[root@server ~]# ww=q2
[root@server ~]# echo $qq
q1
[root@server ~]# echo $ww
q2
# 创建一个子shell
[root@server ~]# bash
Welcome to 5.10.0-182.0.0.95.oe2203sp3.x86_64
System information as of time: Tue May 27 09:12:20 PM CST 2025
System load: 0.00
Processes: 148
Memory used: 9.1%
Swap used: 0%
Usage On: 8%
IP address: 192.168.200.10
Users online: 2
# 环境变量有效
[root@server ~]# echo $qq
q1
# 但是普通变量没有用
[root@server ~]# echo $ww
-
将普通变量转换成环境变量
-
export 普通变量
#
[root@server ~]# export ww
[root@server ~]# echo $ww
q2
3、变量的引用方式
1、$变量名和${}
[root@server ~]# A100=hell0
# $变量名,引用变量名的值
[root@server ~]# echo $A100
hell0
[root@server ~]# echo "$A100 123"
hell0 123
# ${变量名} 变量名的内容输出,括号外的内容正常输出,通常用来做字符串的拼接
[root@server ~]# echo ${A100}123
hell0123
4、查看变量和取消变量
- set查看所有变量
[root@server ~]# set | head
A100=hell0
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob:extquote:force_fignore:globasciiranges:histappend:interactive_comments:login_shell:progcomp:promptvars:sourcepath
BASHRCSOURCED=Y
BASH_ALIASES=()
BASH_ARGC=([0]="0")
BASH_ARGV=()
BASH_CMDS=()
BASH_COMPLETION_VERSINFO=([0]="2" [1]="11")
BASH_LINENO=()
- 查看环境变量
[root@server ~]# env
SHELL=/bin/bash
HISTCONTROL=ignoredups
HISTSIZE=1000
HOSTNAME=server
qq=q1
PWD=/root
LOGNAME=root
MOTD_SHOWN=pam
HOME=/root
LANG=en_US.UTF-8
- unset取消变量,环境变量和普通变量都可以进行取消
[root@server /]# unset A100
[root@server /]# echo $A100
1、重要的环境变量
- PATH变量,存储了系统中所有可执行路径
# 创建一个命令
[root@server tmp]# vim qq
[root@server tmp]# chmod +x qq
[root@server tmp]# ls
qq
[root@server tmp]# ./qq
123
[root@server tmp]# cd
[root@server ~]# qq
-bash: qq: command not found
# 加入到path路径下,这样就可以随时的使用这个命令了
[root@server ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@server ~]# PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/tmp/
[root@server ~]# q
qq quote quote_readline
[root@server ~]# qq
123
- HOME变量存储的家目录路径
二、bash shell中用户与脚本的交互方式
1、$1等符号
- 使用位置化参数给脚本传参,执行脚本时后面接的参数
[root@server opt]# cat openeuler.sh
echo hello $1
[root@server opt]# ./openeuler.sh a1
hello a1
-
$1到$9和$
-
$1表示脚本的第一个参数
-
$0 表示脚本的路径
# 在哪里执行脚本,就显示脚本的路径
[root@server opt]# ./openeuler.sh
./openeuler.sh
[root@server opt]# cd /
[root@server /]# /opt/openeuler.sh
/opt/openeuler.sh
[root@server /]# cat /opt/openeuler.sh
echo $0
-
$# 显示脚本一共有几个参数
-
非常有用,就是创建用户的时候,需要传入三个参数,但是有的时候只传入了2个参数,因此使用$#判断是否传入了三个参数,判断成功了,就执行后面的操作
[root@server opt]# cat openeuler.sh
echo $#
[root@server opt]# ./openeuler.sh a1 12
2
2、接收用户输入
-
read -p "(提示信息)" 变量名
-
-s输入密码的时候,不可见
-
-t 设置超时时间,超时就直接跳过,执行下一行
[root@server opt]# cat openeuler.sh
read -p "input name:" get_name
echo $get_name
[root@server opt]# ./openeuler.sh
input name:asd
asd
三、bash shell中的条件测试语句
-
命令的返回值为0到255,0表示命令执行成功,非0表示命令执行失败
-
$? 表示上一个命令的返回值为多少
1、逻辑运算符
1、逻辑与
-
&& 逻辑与,命令1 && 命令2
-
当第一条命令的返回值为0时,则执行第二条命令,若第一条命令不为0时,第二条命令不执行
-
2个命令都为真,表达式就为真
# 判断主机能不能上网
# 访问一次
[root@server opt]# ping -c 1 qq.com && ifconfig
# 判断用户是否存在
[root@server opt]# id root &> /dev/null && echo ok
ok
2、逻辑或
-
命令1 || 命令2
-
当命令1返回值为0时,则不执行命令2,若返回值不为0时,则执行命令2
-
一个结果为真,整个表达式的结果为真
# 判断用户是否存在,不存在创建,存在输出用户信息
[root@server opt]# id root || useradd root
uid=0(root) gid=0(root) groups=0(root)
# 判断某个文件是否存在,如果文件存在,则输出文件信息,,如果文件不存在则创建文件
[root@server opt]# ls file.sh || touch file.sh
ls: cannot access 'file.sh': No such file or directory
[root@server opt]# ls
file.sh nginx-1.22.1.tar.gz nginx-1.25.4.tar.gz
nginx-1.22.1 nginx-1.25.4 openeuler.sh
3、结合起来
# 编写一个检测ip地址是否存活的脚本,如果ip地址正在被使用,则输出ip ok ,如果ip 地址没有被使用的话,则输出ip error ,要求该ip地址是用户手工输入通过脚本接收
[root@server opt]# cat openeuler.sh
#!/bin/bash
ping -c 1 -W 1 $1 &> /dev/null && echo $1 is ok || echo $1 is error
[root@server opt]# ./openeuler.sh 192.168.200.10
192.168.200.10 is ok
4、条件测试语句
-
test 在linux中专门用来进行条件测试
-
test 表达式
-
[条件表达式]
-
[[条件表达式]]
-
比较数值

# [[]] 这个是非常重要的,可以适合多种条件测试
# 逻辑与和逻辑或都在这个双层括号里面使用
[root@server opt]# a1=100
[root@server opt]# a2=100
[root@server opt]# a3=200
[root@server opt]# [[ $a1 -eq $a2 && $a3 -gt $a1 ]]
[root@server opt]# echo $?
0
- 比较字符串

- $()引用一条命令的执行结果作为变量的值
[root@server opt]# [ $(ifconfig ens33 | grep netmask | awk '{print $2}') == "192.168.200.10" ]
[root@server opt]# echo $?
0
# 因此的话,写脚本的时候可以这样定义
get_ip = $(ifconfig ens33 | grep netmask | awk '{print $2}')
# get_ip变量名=值
- 文件测试

-
布尔运算符,在[] 里面可以使用
-
test里面使用的
-
-a 逻辑与,当2个或者多个表达式同时成立,结果为真
-
-o 逻辑或,有一个成立,结果为真
-
-! 逻辑非,结果为真,取假
[root@server opt]# [ -f /etc/hostname -a -d /opt ]
[root@server opt]# echo $?
0
# 对结果取反
[root@server opt]# [ ! -f /etc/hostname ]
[root@server opt]# echo $?
1
四、程序语句
1、判断语句
1、if语句
-
if适合未知结果的判断
-
if 的格式
if 条件表达式;then
执行代码
elif 条件表达式;then
执行代码
else
执行代码
fi
# 单分支结构
[root@server opt]# cat openeuler.sh
#!/bin/bash
if id root &> /dev/null
then
echo "root"
fi
[root@server opt]# cat openeuler.sh
#!/bin/bash
if id asd &> /dev/null;then
echo "存在"
else
echo "不存在"
fi
[root@server opt]# cat openeuler.sh
#!/bin/bash
if [ -d /opt/test ];then
echo "test is d"
elif [ -f /opt/test ];then
echo "test is f"
else
echo "test other"
fi
2、case语句
-
已知的结果
-
适合于程序菜单
-
语句结束,用分号结束即可
[root@server opt]# cat openeuler.sh
#!/bin/bash
echo "1 启动服务"
echo "2 停止服务"
echo "3 重启服务"
read -p "input number:" get_num
case $get_num in
1)
systemctl start httpd
;;
2)
systemctl stop httpd
;;
3)
systemctl restart httpd
;;
*) # 不符合以上结果的话,执行这个
echo "输入有问题"
;;
esac
[root@server opt]# ./openeuler.sh
1 启动服务
2 停止服务
3 重启服务
input number:6
输入有问题
2、循环语句
1、for循环
- 基于列表的循环
for 变量名 in 列表元素
do
循环体
done
# 使用for完成用户列表的批量创建,并且设置用户密码为openeuler
[root@server opt]# cat user_list
it_001
it_002
it_003
[root@server opt]# cat for_daemon.sh
#!/bin/bash
for i in $(cat user_list)
do
useradd $i
echo user $i create
done
# 检测主机ip是否存活
[root@server opt]# cat ip_check.sh
#!/bin/bash
for i in {1..10}
do
ping -c 1 -W 1 192.168.200.$i &>/dev/null && echo $i is ok || echo $i is error
done
2、while循环
- 条件满足,则循环,不满足则不循环
while 条件表达式
do
循环体
done
- 编写一个创建用户的脚本,脚本要求用户输入uid,如果用户输入的uid已经存在,则提示用户重新输入,如果输入的uid不存在,则创建用户
[root@server opt]# cat while_user.sh
#!/bin/bash
read -p "input_name:" get_name
read -p "input_uid:" get_uid
while id $get_uid &> /dev/null # 检测uid是否重复,重复则执行循环
do
read -p "input_uid:" get_uid # 重复则,再次输入uid
done
useradd -u $get_uid $get_name
echo "$get_name is create"
3、until循环
- 条件满足不循环,条件不满足则循环
until 条件表达式
do
循环体
done
- 通常用在服务器开机检测,或者自动化脚本等待开机场景
#!/bin/bash
until ping -c 1 192.168.200.10 &> /dev/null
do
sleep 3
echo wait configure
done
echo 192.168.200.10 is ok
# 这个ip如果通了,就结束了循环了
# 如果这个ip通不了,一直循环,
# 适合与服务器开机检测
4、循环中断
- break,立刻中断所有的循环,当循环几次后,没有意义就退出整个循环
# 循环到第五次后就退出整个循环
[root@server opt]# cat break.sh
#!/bin/bash
for i in $(seq 1 10)
do
echo $i
if [ $i -eq 5 ];then
break
fi
done
12
- continue中断本次循环,继续下次循环
# 循环到第五次的时候,退出,进行下一次循环
#!/bin/bash
for i in $(seq 1 10)
do
if [ $i -eq 5 ];then
continue
fi
echo $i
done
- 用户存在,不创建,不存在,创建用户
[root@server opt]# cat user.sh
#!/bin/bash
for i in $(cat user_list)
do
# 用户存在中断了循环,继续下次循环
id $i &> /dev/null && echo $i is error && continue
useradd $i
echo $i user create
done
[root@server opt]# cat user_list
it_001
it_002
it_003
it_004
五、shell脚本运行方式
-
绝对路径,需要脚本具有执行权限
-
相对路径,脚本需要执行权限
-
bash 脚本不需要执行权限
-
source 在当前shell中执行,或者 . 来执行脚本,不需要执行权限
source 脚本
. 脚本
-
bash -x 脚本文件名
-
跟踪脚本怎么运行的
[root@server opt]# bash -x user.sh
++ cat user_list
+ for i in $(cat user_list)
+ id it_001
+ echo it_001 is error
it_001 is error # 终端显示的
+ continue
+ for i in $(cat user_list)
+ id it_002
+ echo it_002 is error
it_002 is error
+ continue
+ for i in $(cat user_list)
+ id it_003
+ echo it_003 is error
it_003 is error
+ continue
+ for i in $(cat user_list)
+ id it_004
+ echo it_004 is error
it_004 is error
+ continue
脚本的三要素
- 解释器,注释,程序语句

浙公网安备 33010602011771号