shell是一种脚本语言,那么,就必须有解释器来执行这些脚本
脚本编写格式
#!/bin/bash
,脚本的开始必须要添加这一行
#
上面中的 #!
是一种约定标记,他告诉系统这个脚本需要什么样的解释器来执行
变量
变量的定义和变量的提取
shell变量只能以字母开头
定义变量使用小写和大写字母,特殊字符只能是_
变量的名字需要通俗易懂,通过名字就应该大致的知到变量的含义
变量使用小写,可能会与linux命令冲突,尽量使用大写
bash
[root@bogon ~]# A=wyz
[root@bogon ~]# echo $A
wyz
bash
[root@bogon ~]# a=/etc/hosts
[root@bogon ~]# echo $a
/etc/hosts
[root@bogon ~]# ls $a
/etc/hosts
[root@bogon ~]# cat $a
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
命令替换
将变量定义为一条命令,使用()
或者``,就能够将命名定义为一条命令
bash
[root@bogon ~]# ip a show ens160 | grep inet | grep ens160| awk '{print $2}' | cut -d'/' -f1
192.168.100.129
[root@bogon ~]# IP=$(ip a show ens160 | grep inet | grep ens160| awk '{print $2}' | cut -d'/' -f1)
[root@bogon ~]# echo $IP
192.168.100.129
特殊变量
特殊变量有$$,$?,$0,$1,2,@,\*,#
:当前进程的ID $`?`:列出上一条命令的执行状态。0:正常执行,非0:执行错误 $0:表示脚本文件的执行路径,大多数情况会列出脚本的名字 $1:表示传给脚本的第一个参数 $2:表示传给脚本的第一个参数 $@和$\*:表示传给脚本的所有参数 $#:表示传给脚本参数的数量 ```bash ## 演示
[root@bogon ~]# echo $$
2900
[root@bogon ~]# ps aux | grep bash
root 2871 0.0 0.1 8688 5524 pts/0 Ss+ 13:54 0:00 -bash
root 2900 0.0 0.1 8688 5492 pts/1 Ss 13:57 0:00 -bash
root 2981 0.0 0.0 6408 2180 pts/1 S+ 14:19 0:00 grep --color=auto bash
[root@bogon ~]#
```bash
# 演示$?
[root@bogon ~]# ls
anaconda-ks.cfg script text.txt
[root@bogon ~]# echo $?
0
[root@bogon ~]# LL
-bash: LL: command not found
[root@bogon ~]# echo $?
127
bash
# 演示$0、$1、$2、$@、$*、$#
写一个简单的脚本,运行一下
#!/bin/bash
echo "File Name: $0"
echo "First Parameter: $1"
echo "second Parameter: $2"
echo "Quoted Values: $@"
echo "Quoted Values: $*"
echo "Total Number of Parameters: $#"
[root@bogon script]# ./spec-var.sh tes ssd ad
File Name: ./spec-var.sh
First Parameter: tes
First Parameter: ssd
Quoted Values: tes ssd ad
Quoted Values: tes ssd ad
Total Number of Parameters: 3
脚本的后面有三个参数分别是 tes,ssd和ad,在运行后可以看到
$0:显示了脚本的路径
$1:显示了定义的第一个参数
$2:显示的定义的第一和第二两个参数
@和*:显示了给脚本的所有参数
$#:显示了参数的数量
环境变量
保证系统稳定运行的变量,不能随便改
env可以列出环境变量,不建议更改
bash
[root@bogon ~]# env
SHELL=/bin/bash
HISTCONTROL=ignoredups
HISTSIZE=1000
HOSTNAME=bogon
PWD=/root
LOGNAME=root
XDG_SESSION_TYPE=tty
MOTD_SHOWN=pam
HOME=/root
LANG=en_US.UTF-8
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.webp=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.m4a=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.oga=01;36:*.opus=01;36:*.spx=01;36:*.xspf=01;36:
SSH_CONNECTION=192.168.100.1 12445 192.168.100.129 22
XDG_SESSION_CLASS=user
SELINUX_ROLE_REQUESTED=
TERM=xterm-256color
LESSOPEN=||/usr/bin/lesspipe.sh %s
USER=root
SELINUX_USE_CURRENT_RANGE=
SHLVL=1
XDG_SESSION_ID=13
XDG_RUNTIME_DIR=/run/user/0
SSH_CLIENT=192.168.100.1 12445 22
DEBUGINFOD_URLS=https://debuginfod.centos.org/
which_declare=declare -f
PATH=/root/.local/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
SELINUX_LEVEL_REQUESTED=
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/0/bus
MAIL=/var/spool/mail/root
SSH_TTY=/dev/pts/1
BASH_FUNC_which%%=() { ( alias;
eval ${which_declare} ) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot $@
}
_=/usr/bin/env
OLDPWD=/root/script
shell脚本的条件判断
shell对于缩进没有要求
判断以一条命令是否执行成功
bash
#!/bin/bash
ls >> /dev/null
if [ "$?" == 0 ] ## 执行条件
then
echo "命令执行成功" ## 执行命令
else
echo "命令执行失败" ## 执行命令
fi
如果上一条命令执行成功,会输出"命令执行成功",如果不成功,会输出"命令执行失败"
bash
[root@bogon script]# cat if.sh
#!/bin/bash
ls >> /dev/null
if [ "$?" == 0 ]
then
echo "命令执行成功"
else
echo "命令执行失败"
fi
[root@bogon script]# chmod +x if.sh
[root@bogon script]# ./if.sh
命令执行成功
bash -x + 脚本,可以列出脚本的执行过程
bash
[root@bogon script]# bash -x ./if.sh
+ ls
+ '[' 0 == 0 ']'
+ echo 命令执行成功
命令执行成功
判断一个文件是否存在
bash
#!/bin/bash
if [ -f anaconda-ks.cfg]
then
echo "file exists"
else
echo "file not found"
fi
bash
[root@bogon script]# cat if1.sh
#!/bin/bash
if [ -f anaconda-ks.cfg ]
then
echo "file exists"
else
echo "file not found"
fi
[root@bogon script]# chmod +x if1.sh
[root@bogon script]# ./if1.sh
file exists
shell的与and或
&&
:与,就是英文中的and,只有前面的命令正确的执行了,才会执行&&
后面的命令
||
:或,就是英文中的or,前后两个只要有一个正确,就算正确
&&
和||
被称为逻辑运算
&&
:与
命令连接符,只有前面的命令正确的执行了,才会执行&&
后面的命令
bash
## 两条命令都正确,使用$?查看
[root@bogon script]# ls && ls
anaconda-ks.cfg hello.sh if1.sh if.sh ping.sh spec-var.sh
anaconda-ks.cfg hello.sh if1.sh if.sh ping.sh spec-var.sh
[root@bogon script]# echo $?
0
## 两条命令只有后面的命令正确,使用$?查看
[root@bogon script]# Ls && ls
-bash: Ls: command not found
[root@bogon script]# echo $?
127
## 两条命令只有前面的命令正确,使用$?查看
[root@bogon script]# ls && Ls
anaconda-ks.cfg hello.sh if1.sh if.sh ping.sh spec-var.sh
-bash: Ls: command not found
[root@bogon script]# echo $?
127
## 两条命令都不正确,使用$?查看
[root@bogon script]# Ls && Ls
-bash: Ls: command not found
[root@bogon script]# echo $?
127
就是说只有两个命令都正确,这条命令才算正确
使用 &&
连接的多条命令,可以看成是一条命令
||
:或
命令连接符,只有前面的命令执行失败错误了,才会执行||
后面的命令
bash
[root@bogon script]# ls || echo 0
anaconda-ks.cfg hello.sh if1.sh if.sh ping.sh spec-var.sh
[root@bogon script]# echo $?
0
[root@bogon script]# Ls || echo 0
-bash: Ls: command not found
0
[root@bogon script]# echo $?
0
shell的条件分支语句(case)
bash
#!/bin/bash
echo "Input a number between 1 to 4"
echo "Your number is:\c"
read aNum
case $aNum in
1) echo 'you select 1';;
2) echo 'you select 2';;
3) echo 'you select 3';;
4) echo 'you select 4';;
*) echo 'you do not select a number between 1 to 4';;
esac
read:可以从用户的输入读取变量,aNum
就是指下面的变量$aNum
for循环
bash
#!/bin/bash
for i in 1 2 3 4 5 ## 这里也可以写成{1..5}
do
echo "The value is:$1"
done
循环1到5,并将其输出出来
while循环
bash
#!/bin/bash
COUNTER=0
while [ $COUNTER -lt 5]
do
COUNTER=`expr $COUNTER + 1`
echo $CONTER
done
-
eq:等于(equal)
-
lt:小于(less than)
-
le:小于等于(less equal)
-
gt:大于(greater than)
-
ge:大于等于(greater equal)
-
expr:进行计算的命令,linux中,只有使用了这个命令,才能进行算术运算
bash
[root@bogon script]# cat while.sh
#!/bin/bash
COUNTER=0
while [ $COUNTER -lt 5 ]
do
COUNTER=`expr $COUNTER + 1`
echo $COUNTER
done
[root@bogon script]# bash while.sh
1
2
3
4
5
bash
#!/bin/bash
while true
do
sleep 1
echo "hello word"
done
这种执行建议加上sleep
,终止脚本只能通过Ctrl+C
untill循环
主要用于交互式脚本,搭配read
语句使用
bash
#!/bin/bash
COUNTER=0
until [ $COUNTER -lt 5 ]
do
COUNTER=`expr $COUNTER + 1`
echo $COUNTER
done
直到什么条件满足[ $COUNTER -lt 5 ]
,才会执行
交互式脚本,强制执行某个命令,要不执行,要不退出
bash
echo "2"
echo "1"
until [[ "$aNum" =~ ^[1-2]$ ]] # 以1或2开头,或者以1或2结尾
do
read -rp " aNum [1-2]: " -e -i 1 aNum # -e和-i是指默认以后面的1输出
done
Shell脚本函数
bash
#!/bin/bash
function check()
{
echo -e "=====================世界你好======================="
}
-
function:定一个函数
-
check:函数名,里面不用加参数,使用的时候直接调用
定义这个函数之后,在下面的代码中只需输入 check,就可以调用这个命令
一般我们可以将一个函数文件写到一个单独的文件里面,需要时,直接使用source
直接调用这个文件