1.shell脚本以#!/bin/bash开头
2.小练习
vi test.sh
#!/bin/bash
echo "hello world" #屏幕上打印出“hello world”
mkdir /home/dengchao/temp #创建temp目录
touch /home/dengchao/temp/a.txt #创建a.txt文件
3.执行shell文件(两种执行方法)
a)sh test.sh
b)chmod +x tesh.sh
./test.sh
4.单引号和双引号的区别
单引号:直接以字符串的形式输出
双引号:可以数据变量
[root@VM_191_213_centos ~]# VAR2='hello world $VAR1'
[root@VM_191_213_centos ~]# VAR3="hello world $VAR1"
[root@VM_191_213_centos ~]# echo $VAR2
hello world $VAR1
[root@VM_191_213_centos ~]# echo $VAR3
hello world 123
[root@VM_191_213_centos ~]#
5.删除变量
unset VAR1
[root@VM_191_213_centos ~]# unset VAR1
[root@VM_191_213_centos ~]# echo $VAR1
[root@VM_191_213_centos ~]#
6.环境变量
a)全局变量
1)查看全局变量
env
2)演示
[root@VM_191_213_centos ~]# export var=123
[root@VM_191_213_centos ~]# echo $var
123
[root@VM_191_213_centos ~]# vi a.sh
#!/bin/bash
echo $var
[root@VM_191_213_centos ~]# sh a.sh #引用全局变量成功
123
[root@VM_191_213_centos ~]#
b)局部变量
1)演示
[root@VM_191_213_centos ~]# echo $var
123
[root@VM_191_213_centos ~]# vi a.sh
#!/bin/bash
echo $var
[root@VM_191_213_centos ~]# sh a.sh #引用局部变量失败
[root@VM_191_213_centos ~]#
7.设置环境变量
a)演示
[root@VM_191_213_centos ~]# vi /home/dengchao/backup.sh
#!/bin/bash
echo "backup data is ok"
"/home/dengchao/backup.sh" [New] 2L, 37C written
[root@VM_191_213_centos ~]# chmod +x /home/dengchao/backup.sh
[root@VM_191_213_centos ~]# /home/dengchao/backup.sh
backup data is ok
[root@VM_191_213_centos ~]# PATH=/home/dengchao/:$PATH
[root@VM_191_213_centos ~]# backup.sh
backup data is ok
[root@VM_191_213_centos ~]#
b)shell位置变量
$0 表示脚本文件名称
$1,$2,$3,$4...$n 分别代表不同的位置变量
演示如下:
[root@VM_191_213_centos dengchao]# vi print.sh
echo "第二个参数是:$2"
#!/bin/bash
echo "脚本文件的名称是:$0"
echo "第一个参数是:$1"
echo "第二个参数是:$2"
echo "第三个参数是:$3"
echo"第四个参数是:$4"
"print.sh" [New] 6L, 165C written
[root@VM_191_213_centos dengchao]# sh print.sh 111 222 333 555
脚本文件的名称是:print.sh
第一个参数是:111
第二个参数是:222
第三个参数是:333
第四个参数是:555
[root@VM_191_213_centos dengchao]# ^C
c)特殊变量
$*:表示这个程序的所有参数
$#:表示这个程序的参数个数
$$:表示程序的进程ID
$!:执行上一个后台指令的PID
$?:表示上一个程序执行返回的结果
演示:
[root@xuegod63 ~]# vim special_variable.sh #写入以一下内容
#!/bin/bash
echo "$* 表示这个程序的所有参数 "
echo "$# 表示这个程序的参数个数"
echo "$$ 表示程序的进程ID "
touch /tmp/b.txt &
echo "$! 执行上一个后台指令的PID"
echo "$$ 表示程序的进程ID "
echo "$? 表示上一个程序执行返回结果 "
[root@xuegod63 ~]# bash special_variable.sh 11 22 33 44 55
11 22 33 44 55 表示这个程序的所有参数
11 22 33 44 55 表示这个程序的所有参数
5 表示这个程序的参数个数
45502 表程序的进程ID
45504 执行上一个后台指令的PID
45502 表程序的进程ID
0 表示上一个程序执行返回结果
8.数学运算
1)expr
a)对数字的处理
演示1:
[root@VM_191_213_centos ~]# expr 2 \* 3
6
[root@VM_191_213_centos ~]# ^C
演示2:
[root@VM_191_213_centos ~]# expr 3 \+ 4
7
[root@VM_191_213_centos ~]#
b)对字符串的处理
[root@VM_191_213_centos ~]# expr length "ni hao"
6
[root@VM_191_213_centos ~]# expr substr "ni hao" 2 4
i ha
[root@VM_191_213_centos ~]#
2)$(())
演示1:
[root@VM_191_213_centos ~]# b=$((2+3))
[root@VM_191_213_centos ~]# echo $b
5
[root@VM_191_213_centos ~]#
演示2:
[root@VM_191_213_centos ~]# echo $((b++))
5
[root@VM_191_213_centos ~]# echo $((b++))
6
[root@VM_191_213_centos ~]#
9.read命令
1)入门
[root@VM_191_213_centos ~]# read a b
aaa bbb
[root@VM_191_213_centos ~]# echo $a
aaa
[root@VM_191_213_centos ~]# echo $b
bbb
[root@VM_191_213_centos ~]# echo $a $b
aaa bbb
2)常见用法
a)read -s 隐藏输入的信息
[root@VM_191_213_centos ~]# read -s passwd
[root@VM_191_213_centos ~]# echo $passwd
aaaa
[root@VM_191_213_centos ~]#
b)read -p 提示信息
[root@VM_191_213_centos ~]# read -p "input your passwd:" passwd
input your passwd:1235
[root@VM_191_213_centos ~]# echo $passwd
1235
[root@VM_191_213_centos ~]#
c)read -t+时间 限制输入的时间(单位:秒)
[root@VM_191_213_centos ~]# read -t 5 a ###5秒钟不输入就结束
12
[root@VM_191_213_centos ~]# echo $a
12
[root@VM_191_213_centos ~]#
d)read -n+数字 输入长度限制
[root@VM_191_213_centos ~]# read -n 3 aaa ###长度超过三个自动结束
dfafsafsdaf[root@VM_191_213_centos ~]#
dfafsafsdaf[root@VM_191_213_centos ~]# echo $aaa
dfa
[root@VM_191_213_centos ~]#
e)read -r 可以输入特殊字符
[root@VM_191_213_centos ~]# read -r name
&*\\\\
[root@VM_191_213_centos ~]# echo $name
&*\\\\
[root@VM_191_213_centos ~]#
演示:
#!/bin/bash
read -p "请输入您的姓名:" name
read -p "请输入您的性别:" sex
read -p "请输入您的年龄:" age
cat<<eof
**********************
您的姓名是:$name
您的性别是:$sex
您的年龄是:$age
**********************
eof
输出结果:
[root@VM_191_213_centos dengchao]# sh test-read.sh
请输入您的姓名:dengchao
请输入您的性别:mail
请输入您的年龄:28
**********************
您的姓名是:dengchao
您的性别是:mail
您的年龄是:28
**********************
[root@VM_191_213_centos dengchao]#
10.if语句
1)单分支
#!/bin/bash
if ls /home;then
echo "it is ok!"
fi
[root@VM_191_213_centos dengchao]# sh if-1.sh
dengchao git id_rsa.pub m17 mlog
it is ok!
[root@VM_191_213_centos dengchao]#
2)双分支
#!/bin/bash
if grep root /etc/passwd;then
echo "it is exsist"
else
echo "it is not exsist"
fi
[root@VM_191_213_centos dengchao]# sh if-2.sh
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
it is exsist
[root@VM_191_213_centos dengchao]#
3)多分支
#!/bin/bash
read -p "input a user:" tu
if grep $tu /etc/passwd;then
echo "$tu user is exsist"
elif ls -d /home/$tu;then
echo "$tu user has not exsist"
echo "$tu directory has exsist in home"
else
echo "$tu directory has not exsist"
fi
[root@VM_191_213_centos dengchao]# sh if-3.sh
input a user:aaa
/home/aaa
aaa user has not exsist
aaa directory has exsist in home
[root@VM_191_213_centos dengchao]#
11.test命令
1)数值比较
-eq:等于
-ne:不等于
-gt:大于
-ge:大于等于
-lt:小于
-le:小于等于
演示:
[root@VM_191_213_centos dengchao]# vi test-1.sh
#!/bin/bash
read -p "input two variable var1 and var2:" var1 var2
if [ $var1 -gt $var2 ];then
echo "$var1 > $var2"
elif [ $var1 -lt $var2 ];then
echo "$var1 < $var2"
else
echo "$var1 = $var2"
fi
结果测试:
[root@VM_191_213_centos dengchao]# sh test-1.sh
input two variable var1 and var2:22 33
22 < 33
[root@VM_191_213_centos dengchao]# sh test-1.sh
input two variable var1 and var2:33 22
33 > 22
[root@VM_191_213_centos dengchao]# sh test-1.sh
input two variable var1 and var2:22 22
22 = 22
[root@VM_191_213_centos dengchao]#
2)字符串比较
==:相等
!=:不等
-n:字符串长度是否为空
-z:字符串长度是否为0
str1 > str:str1大于str2为真
str1 < str2:str1小于str2为真
演示:
read -p "please input a user:" name
if [ $name == $USER ];then
echo "you input name is: $name"
elif [ $name != $USER ];then
echo "you input name is not current system user"
if [ $name \> $USER];then ####字符串比较大小时,必须要用转义符;否则shell会当成重定向来处理
echo "$name > $USER"
elif [ $name \< $USER];then
echo "$name < $USER"
else
echo "you input name is not right"
fi
elif [ $name -z ];then
echo "you input name length is 0"
elif [ $name -n ];then
echo "you input name is null"
else
echo "you input name not right"
fi
测试结果:
[root@VM_191_213_centos dengchao]# sh test-2.sh
please input a user:root
you input name is: root
[root@VM_191_213_centos dengchao]# sh test-2.sh
please input a user:dengchao
you input name is not current system user
dengchao < root
[root@VM_191_213_centos dengchao]# sh test-2.sh
please input a user:zoot
you input name is not current system user
zoot > root
[root@VM_191_213_centos dengchao]# sh test-2.sh
please input a user:
test-2.sh: line 3: [: ==: unary operator expected
test-2.sh: line 5: [: !=: unary operator expected
you input name length is 0
[root@VM_191_213_centos dengchao]#
3)文件比较
-e 文件名:如果文件或目录存在则为真
-r 文件名:如果文件存在且可读则为真
-w 文件名:如果文件存在且可写则为真
-x 文件名:如果文件存在且可执行则为真
-s 文件名:如果文件存在且至少有一个字符则为真
-d 文件名.:如果文件存在且为目录则为真
-f 文件名:如果文件存在且为普通文件则为真
-c 文件名:如果文件存在且为字符型文件则为真
-b 文件名:如果文件存在且为块特殊文件则为真
file1 -nt fle2:检查file1是否比file2新
file1 -ot file2:检查file1是否比file2旧
演示:
[root@VM_191_213_centos dengchao]# vi test-3.sh
#!/bin/bash
if [ -e /etc/passwd ];then
echo ok
else
echo err
fi
演示结果:
[root@VM_191_213_centos dengchao]# sh test-3.sh
ok
[root@VM_191_213_centos dengchao]#
12.流程控制语句
1)case语句
语法:
case?????变量或表达式?????in
?????? ???????变量或表达式1)
?????????????????????命令序列1
?????????????????????;;
????????????变量或表达式2)
?????????????????????命令序列2
?????????????????????;;
?????????????????????……
???????????????????? *)??
?????????????????????默认命令序列
esac
案例1:编写一个操作文件的脚本
#!/bin/bash
#########################################################################
# File Name: case-1.sh
# Author: dengchao
#########################################################################
cat<<eof
*************
**1.backup**
**2.copy **
**3.quit **
*************
eof
read -p "input a choice:" op
case $op in
1|backup)
echo "backup is ok"
;;
2|copy)
echo "copy is ok"
;;
3|quit)
exit
;;
*)
echo "error"
esac
演示结果:
[root@VM_191_213_centos dengchao]# sh case-1.sh
*************
**1.backup**
**2.copy **
**3.quit **
*************
input a choice:1
backup is ok
[root@VM_191_213_centos dengchao]# sh case-1.sh
*************
**1.backup**
**2.copy **
**3.quit **
*************
input a choice:2
copy is ok
[root@VM_191_213_centos dengchao]# sh case-1.sh
*************
**1.backup**
**2.copy **
**3.quit **
*************
input a choice:3
[root@VM_191_213_centos dengchao]# sh case-1.sh
*************
**1.backup**
**2.copy **
**3.quit **
*************
input a choice:dsadsf
error
[root@VM_191_213_centos dengchao]#
案例2:编写一个启动apache服务脚本
case $1 in
start)
systemctl $1 httpd
systemctl status httpd
echo "httpd start"
;;
stop)
systemctl $1 httpd
systemclt status httpd
echo "httpd stop"
;;
restart)
systemctl $1 httpd
systemctl status httpd
echo "httpd restart"
;;
status)
systemctl $1 httpd
;;
*)
echo "USAGE: $0 start|stop|restart|status"
esac
2)循环语句
a)for循环
for-do-done
语法格式:
for var in list
do
commands
done
或:
for var in list ; do
commands
done
演示1:
[root@VM_191_213_centos dengchao]# vi for-1.sh
#!/bin/bash
for i in a b c d
do
echo $i
done
演示2:从变量中取值
[root@VM_191_213_centos dengchao]# vi for-2.sh
#!/bin/bash
list="a b v c d"
for i in $list
do
echo $i
done
演示3:从命令中取值
[root@VM_191_213_centos dengchao]# vi for-3.sh
#!/bin/bash
for i in `cat /etc/hosts`
do
echo $i
done
演示4: IFS=. 自定义分隔符
[root@VM_191_213_centos dengchao]# vi for-4.sh
#!/bin/bash
IFS=.
for i in `cat /etc/hosts`
do
echo $i
done
演示5:c语言风格的for循环(多变量)
[root@VM_191_213_centos dengchao]# vi for-5.sh
#!/bin/bash
for (( i=1,j=9 ; i<10 ;i++,j--))
do
echo "$i######$j"
done
b)while循环
while?测试命令
do
命令
done
演示1:
[root@VM_191_213_centos dengchao]# vi while-1.sh
#!/bin/bash
var=10
while [ $var -gt 0 ]
do
echo $var
var=$(($var-1))
done
演示2:
[root@VM_191_213_centos dengchao]# vi +6 while-2.sh
#!/bin/bash
var=1
while [ $var -lt 10 ]
do
sum=$(($var*$var))
echo "$var*$var=$sum"
((var++))
done
结果输出:
[root@VM_191_213_centos dengchao]# sh while-2.sh
1*1=1
2*2=4
3*3=9
4*4=16
5*5=25
6*6=36
7*7=49
8*8=64
9*9=81
演示三:99乘法表
[root@VM_191_213_centos dengchao]# vi while-4.sh
#!/bin/bash
for i in `seq 9`
do
for j in `seq $i`
do
echo -n "$i*$j= `echo $(($i*$j))` "
done
echo " "
done
演示结果:
[root@VM_191_213_centos dengchao]# sh while-4.sh
1*1= 1
2*1= 2 2*2= 4
3*1= 3 3*2= 6 3*3= 9
4*1= 4 4*2= 8 4*3= 12 4*4= 16
5*1= 5 5*2= 10 5*3= 15 5*4= 20 5*5= 25
6*1= 6 6*2= 12 6*3= 18 6*4= 24 6*5= 30 6*6= 36
7*1= 7 7*2= 14 7*3= 21 7*4= 28 7*5= 35 7*6= 42 7*7= 49
8*1= 8 8*2= 16 8*3= 24 8*4= 32 8*5= 40 8*6= 48 8*7= 56 8*8= 64
9*1= 9 9*2= 18 9*3= 27 9*4= 36 9*5= 45 9*6= 54 9*7= 63 9*8= 72 9*9= 81
13.三个实战
a)实战-将/opt目录下所有的日志文件全自动打包
[root@xuegod63 ~]# vim log-back.sh
#!/bin/sh
SRC_DIR=/var/log/
DES_DIR=/opt/backup/`date +%Y%m%d`
if
[ ! -d $DES_DIR ] ; then
mkdir -p $DES_DIR
fi
for i in `find $SRC_DIR -name "*.log"`
do
tar czf $i.tgz $i
done
mv /var/log/*.tgz $DES_DIR
ls -lh $DES_DIR
echo "The scripts exec end, Files tar successfully !"
b) 实战-找出192.168.1.1-10网段中,服务器已经关机的IP地址
[root@xuegod63 ~]# vim ping.sh
#!/bin/bash
for i in `seq 10`
do
ping -c 3 192.168.1.$i &>/dev/null
if [ $? -ne 0 ];then
echo "192.168.1.$i is shutdown"
fi
done
c)批量创建帐号并生成随机密码
[root@xuegod63 ~]# vim adduser.sh
#!/bin/bash
for i in degchao{1..10}
do
useradd $i
pass=`date +%s|md5sum|cut -c 1-8`
sleep 1
echo "$i:$pass" >> /tmp/passwd.log
echo $pass |passwd --stdin $i > /dev/null 2>&1
if [ $? -eq 0 ];then
echo "create user is successfully!"
else
echo "create user is failed!"
fi
done
d)批量删除创建的用户
#!/bin/bash
for i in degchao{1..10}
do
userdel -r $i > /dev/null 2>&1
if [ $? -eq 0 ];then
echo "$i has been remove"
else
echo "$i remove fail"
fi
done
14.shift参数左移指令
案例:加法计算器
[root@VM_191_213_centos dengchao]# vi shift.sh
#!/bin/bash
if [ $# -le 0 ];then
echo "参数个数不合法"
fi
sum=0
while [ $# -gt 0 ]
do
sum=$[$sum+$1]
shift
done
echo "The result is $sum"
15.函数
案例1:
[root@VM_191_213_centos dengchao]# vi fun-1.sh
#!/bin/bash
function fun_1 { #定义函数
echo "hello world"
}
fun_1
案例2:函数名的使用,如果在一个脚本中定义了重复的函数名,那么以最后一个为准
[root@VM_191_213_centos dengchao]# vi fun-2.sh
#!/bin/bash
function fun_2 {
echo "aaaaaa"
}
function fun_2 {
echo "bbbbbb"
}
fun_2
[root@VM_191_213_centos dengchao]# sh fun-2.sh
bbbbbb
[root@VM_191_213_centos dengchao]#
16.sed流编辑
语法格式:sed [options] ‘[commands]’ filename
sed选项|参数:
options:
-a 在当前行下面插入文件
-n 读取下一个输入行,用下一个命令处理新的行而不是用第一个命令
-e 执行多个sed指令
-f 运行脚本
-i 编辑文件内容 ***
-i.bak 编辑的同时创造.bak的备份
-r 使用扩展的正则表达式
命令:
i 在当前行上面插入文件
c 把选定的行改为新的指定的文本
p 打印 ***
d 删除 ***
r/R 读取文件/一行
w 另存
s 查找
y 替换
h 拷贝模板块的内容到内存中的缓冲区。
H 追加模板块的内容到内存中的缓冲区。
g 获得内存缓冲区的内容,并替代当前模板块中的文本。
G 获得内存缓冲区的内容,并追加到当前模板块文本的后面
D 删除\n之前的内容
P 打印\n之前的内容
替换标记:
?数字:表明新文本将替换第几处模式匹配的地方
?g:表示新文本将会替换所有匹配的文本
?\1:子串匹配标记,前面搜索可以用元字符集\(..\),
?&:保留搜索到的字符用来替换其它字符
1)案例1:s 只替换第一个匹配到的字符,将passwd中的root用户替换成xuegod
[root@xuegod63 ~]# sed 's/root/xuegod/' /etc/passwd
xuegod:x:0:0:root:/root:/bin/bash #发现只替换了第一个匹配的root,后面的没有替换
bin:x:1:1:bin:/bin:/sbin/nologin
2)全面替换标记g
[root@xuegod63 ~]# sed 's/root/xuegod/g' /etc/passwd |more
xuegod:x:0:0:xuegod:/xuegod:/bin/bash #全部替换了
3)按行查找替换
写法如下:
用数字表示行范围;$表示行尾
用文本模式配置来过滤
例1:单行替换,将第2行中bin替换成xuegod
[root@xuegod63 ~]# sed '2s/bin/xuegod/' /etc/passwd | more
root:x:0:0:root:/root:/bin/bash
xuegod:x:1:1:bin:/bin:/sbin/nologin
例2:多行替换,如果涉及到多行处理,用逗号表示行间隔。 将第3行到最行尾中bin替换成xuegod
[root@xuegod63 ~]# sed '2,$s/bin/xuegod/' /etc/passwd | more
root:x:0:0:root:/root:/bin/bash
xuegod:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sxuegod:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sxuegod/nologin
4)d 删除第2行到第4行的内容
[root@VM_191_213_centos ~]# cat /etc/hosts
0.0.0.0 pastebin.com
0.0.0.0 nicehash.com
0.0.0.0 f2pool.com
0.0.0.0 onion.to
0.0.0.0onion.glass
0.0.0.0 onion.ly
0.0.0.0 onion.pet
0.0.0.0 tor2web.fyi
0.0.0.0 onion.in.net
0.0.0.0 ponion.mn
0.0.0.0 d2web.org
[root@VM_191_213_centos ~]# sed '2,4d' /etc/hosts
0.0.0.0 pastebin.com
0.0.0.0onion.glass
0.0.0.0 onion.ly
0.0.0.0 onion.pet
0.0.0.0 tor2web.fyi
0.0.0.0 onion.in.net
0.0.0.0 ponion.mn
0.0.0.0 d2web.org
[root@VM_191_213_centos ~]#
5)-i 对原文件修改,保存( 必会 ) 使用场景: 替换或修改服务器配置文件
[root@xuegod63 ~]# cp /etc/passwd /opt/
[root@xuegod63 ~]# sed -i 's/root/xuegod/' /etc/passwd
[root@xuegod63 ~]# head -n 1 /etc/passwd
xuegod:x:0:0:root:/root:/bin/bash
修改IP地址为192.168.1.65
[root@xuegod63 ~]# sed -i 's/IPADDR=192.168.1.63/IPADDR=192.168.1.65/' /etc/sysconfig/network-scripts/ifcfg-ens33
17)cut命令
语法: cut(选项)(参数)
选项
-b:仅显示行中指定范围的字节数;
-c:仅显示行中指定范围的字符;
-d:指定字段的分隔符,默认的字段分隔符为“TAB”;
-f:显示指定字段的内容;
案例1:输出系统中所有用户名
使用 -f 选项提取指定字段,使用 -d 选项指定字段分隔符,这里以:冒号做分隔
案例1:输出系统中所有用户名
使用 -f 选项提取指定字段,使用 -d 选项指定字段分隔符,这里以:冒号做分隔
[root@xuegod63 ~]# cut -f1 -d ":" /etc/passwd
注:其他指令
cut命令可以将一串字符作为列来显示,字符字段的记法:
N-:从第N个字节、字符、字段到结尾;
N-M:从第N个字节、字符、字段到第M个(包括M在内)字节、字符、字段;
-M:从第1个字节、字符、字段到第M个(包括M在内)字节、字符、字段。
上面是记法,结合下面选项将摸个范围的字节、字符指定为字段:
-b 表示字节;
-c 表示字符;
-f 表示定义字段。
例1:打印第1个到第3个字符:
[root@xuegod63 ~]# cut -c1-3 /etc/passwd
例2:打印前2个字符:
[root@xuegod63 ~]# cut -c-2 /etc/passwd
例3:打印从第5个字符开始到结尾:
[root@xuegod63 ~]# cut -c5- /etc/passwd