第十一单元 Bash Scripts
一、Bash脚本基础
1.BASH = GNU Bourne-Again Shell,BASH 是 GNU 组织开发和推广的一个项目。
2.Bash脚本类似批处理,简单来讲就是把许多的指令集合在一起,并提供循环、条件、判断等重要功能,语法简单实用,用以编写程序,大大简化管理员的操作,并可以完成图形工具所无法实现的功能。
3.如何创建新shell脚本?
1)创建包含bash命令的文本文件。文件的第一行应为:
#!/bin/bash
2)使文件可执行(使用chmod +x scripts)
3)将文件放置在用户的$PATH的目录中
~/bin – 用于用户的私有程序
/usr/local/bin – 本地开发、系统上的其他人使用的脚本
/usr/local/sbin - 本地开发、由root使用的脚本直接运行脚本和使用source命令运行脚本是不同的!
4)脚本调试模式:
#!/bin/bash -x
# bash -x scripts
4.引用和转义
引用和转义在shell解析字符串时用于去除字符串中特殊字符或保留词语的特殊含义。这会导致按字面处理字符串,而不是展开变量或将其部分内容视作具有特殊含义。引用有三种类型:
1)弱引用
将字符串放置在双引号中,保留字符串中所有字符的文字值,$、`、\和!字符除外。换言之,变量扩展和命令扩展在双引号内仍起作用。
echo “can I have a $FRUIT”
echo “The current time is $(date +%r).”
2)强引用
将字符串放置在单引号中,保留字符串中所有字符的文字值,同时禁用所有扩展:
echo “Make $$$ Fast”
rm 'untitled folder'
3)转义
非引用的\是转义字符。它保留了下一个字符的文字值。(例如,\$PATH是确切的字符串$PATH,而不是PATH变量的内容。)
echo Make \$\$\$ Fast\!
ls untitled\ folder
[root@server0 ~]# echo # not a comment #
[root@server0 ~]# echo \# not a comment #
# not a comment
[root@server0 ~]# echo \# not a comment \#
# not a comment #
[root@server0 ~]# echo '# not a comment #'
# not a comment #
[root@server0 ~]# echo '$HOME'
$HOME
[root@server0 ~]# echo '`pwd`'
`pwd`
[root@server0 ~]# echo '"Hello,world"'
"Hello,world"
www.westos.org
6[root@server0 ~]# echo "$HOME"
/root
[root@server0 ~]# echo "`pwd`"
/root
[root@server0 ~]# echo ""Hello, world""
Hello, world
[root@server0 ~]# echo "\$HOME"
$HOME
[root@server0 ~]# echo "\`pwd\`"
`pwd`
[root@server0 ~]# echo "\"Hello, world\""
"Hello, world"
5.Shell变量
shell变量用于为稍后在脚本中使用的名称指定值,并且仅限于shell命令行或从中声明变量的脚本。
若要定义或指定值:
FRUIT=apple
若要参考或使用变量:
$FRUIT
${FRUIT}
[root@server0 ~]# FIRST=John
[root@server0 ~]# LAST=Doe
[root@server0 ~]# echo $FIRST $LAST
John Doe
[root@server0 ~]# echo $FIRST_$LAST
Doe
[root@server0 ~]# echo ${FIRST}_$LAST
John_Doe
6.命令替换
命令替换在子shell中执行指定命令并用命令输出替换脚本中的命令替换。
语法:
$(shell command)
示例:
touch datafile.$(id -un)
TODAY=$(date +%Y-%m-%d)
[root@server0 ~]# TAROUTPUT=$(tar cvf /tmp/backup.tar $(find /etc -type f -mtime 1))
tar: Removing leading `/' from member names
[root@server0 ~]# echo $TAROUTPUT
/etc/hosts.allow /etc/hosts.deny /etc/sysconfig/iptables /etc/xinetd.d/tftp /etc/rht
/etc/firewalld/zones/public.xml.old /etc/firewalld/firewalld.conf.old /etc/xinetd.conf
7.算术运算符
算术运算符指的是可以在程序中实现加、减、乘、除等数学运算的运算符。
operator meaning
<VARIABLE>++ 增量后
<VARIABLE>-- 减量后
- 减法
+ 加法
** 幂运算
* 乘法
/ 除法
% 余数
+= 加等
-= 减等
1)Shell计算命令:
用$[]表示数学运算。
# echo $[1+2]
# a=1; echo $[$[$a+1]*2]
用expr表示数学运算。
# echo `expr 1 + 2`
用let指示数学运算。
# let A=1+2
# echo $A
用(())表示数学运算。bash内建功能,效率高。
#!/bin/bash
for ((i=1;i<10;i++))
do
((j+=i))
done
echo $j
8.循环:for循环用于值列表中的相同命令的重复。
[root@server0 ~]# for HOST in host{1..3};do echo $HOST;done
host1
host2
host3
[root@server0 ~]# for NUM in $(seq 2 2 8);do echo $NUM;done
2
4
6
8
1)循环与计算结合:
#!/bin/bash
for ((i=1;i<=100;i++))
do
((j+=i))
#j=`expr $j + $i`
#let j+=i
#j=$[j+=i]
done
echo $j
也可以写成一行:
# for((i=0; i<=100; i++));do j=`expr $j + $i` ;done;echo $j
2)数据库备份示例:
#!/bin/bash
for DB in $(mysql -e "show databases;" -E -N | grep -v '^*' | grep -v 'schema$')
do
echo "Backing up $DB"
mysqldump $DB > /dbbackup/$DB.dump
done
echo ""
for DBDUMP in /dbbackup/*
do
SIZE=$(stat --printf "%s\n" $DBDUMP)
echo "$DBDUMP
$SIZE"
done
二、示例
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# cat test.sh
#!/bin/bash
cat
[root@localhost mnt]# sh test.sh
^Z
[1]+ Stopped sh test.sh
[root@localhost mnt]# ps ef
PID TTY STAT TIME COMMAND
2068 pts/0 Ss 0:00 -bash XMODIFIERS=@im=ibus LANG=en_US.UTF-8 USER=root
2108 pts/0 T 0:00 \_ sh test.sh XDG_SESSION_ID=2 HOSTNAME=localhost.lo
2109 pts/0 T 0:00 | \_ cat XDG_SESSION_ID=2 HOSTNAME=localhost.local
2110 pts/0 R+ 0:00 \_ ps ef XDG_SESSION_ID=2 HOSTNAME=localhost.localdo
1844 tty1 Ss+ 0:00 -bash HOME=/root USER=root SHELL=/bin/bash TERM=linux
[root@localhost mnt]# fg
sh test.sh
^C
[root@localhost mnt]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
[root@localhost mnt]# bash -x test.sh
+ cat
^C
[root@localhost mnt]# a=1
[root@localhost mnt]# echo $a
1
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# sh test.sh
root
[root@localhost mnt]# cat test.sh
#!/bin/bash
echo $USER
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# sh test.sh
LOCAL USER is root
[root@localhost mnt]# cat test.sh
#!/bin/bash
NAME="LOCAL USER is"
echo $NAME $USER
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# cat test.sh
#!/bin/bash
NAME="LOCAL USER is"
echo $NAME $USER
FIRSTNAME=student
FAMNAME=duck
echo my name is $FIRSTNAME_$FAMNAME
[root@localhost mnt]# sh test.sh
LOCAL USER is root
my name is duck
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# cat test.sh
#!/bin/bash
NAME="LOCAL USER is"
echo $NAME $USER
FIRSTNAME=student
FAMNAME=duck
echo my name is ${FIRSTNAME}_$FAMNAME
[root@localhost mnt]# sh test.sh
LOCAL USER is root
my name is student_duck
[root@localhost mnt]# ls
test.sh
[root@localhost mnt]# vim show_ip.sh
[root@localhost mnt]# cat show_ip.sh
#!/bin/bash
IP=`ifconfig eth0 | grep inet | grep inet6 -v | awk -F " " '{print $1}'`
echo "your ipaddress is : $IP"
[root@localhost mnt]# sh show_ip.sh
show_ip.sh: line 2: ifconfig: command not found
your ipaddress is :
[root@localhost mnt]# ifconfig
-bash: ifconfig: command not found
[root@localhost mnt]# yum search ifconfig
Loaded plugins: product-id, search-disabled-repos, subscription-manager
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
rhel7.2 | 4.1 kB 00:00
(1/2): rhel7.2/group_gz | 136 kB 00:00
(2/2): rhel7.2/primary_db | 3.6 MB 00:00
============================== Matched: ifconfig ===============================
net-tools.x86_64 : Basic networking tools
[root@localhost mnt]# yum install net-tools.x86_64 -y
[root@localhost mnt]# ifconfig
ens3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.25.254.64 netmask 255.255.255.0 broadcast 172.25.254.255
inet6 fe80::5054:ff:feb4:9bda prefixlen 64 scopeid 0x20<link>
ether 52:54:00:b4:9b:da txqueuelen 1000 (Ethernet)
RX packets 1932 bytes 143545 (140.1 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1140 bytes 170323 (166.3 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 0 (Local Loopback)
RX packets 4 bytes 344 (344.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 4 bytes 344 (344.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@localhost mnt]# vim show_ip.sh
[root@localhost mnt]# cat show_ip.sh
#!/bin/bash
IP=`ifconfig ens3 | grep inet | grep inet6 -v | awk -F " " '{print $1}'`
echo "your ipaddress is : $IP"
[root@localhost mnt]# sh show_ip.sh
your ipaddress is : inet
[root@localhost mnt]# vim show_ip.sh
[root@localhost mnt]# cat show_ip.sh
#!/bin/bash
IP=`ifconfig ens3 | grep inet | grep inet6 -v | awk -F " " '{print $2}'`
echo "your ipaddress is : $IP"
[root@localhost mnt]# sh show_ip.sh
your ipaddress is : 172.25.254.64
[root@localhost mnt]#
[root@localhost mnt]# hostname
localhost.localdomain
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# vim show_ip.sh
[root@localhost mnt]# cat show_ip.sh
#!/bin/bash
IP=`ifconfig ens3 | grep inet | grep inet6 -v | awk -F " " '{print $2}'`
echo "$(hostname)'s ipaddress is : $IP"
[root@localhost mnt]# sh show_ip.sh
localhost.localdomain's ipaddress is : 172.25.254.64
[root@localhost mnt]#
[root@localhost mnt]# vim num.sh
[root@localhost mnt]# sh num.sh
1
2
3
4
5
[root@localhost mnt]# cat num.sh
#!/bin/bash
for NUM in {1..5}
do
echo $NUM
done
[root@localhost mnt]# vim num.sh
[root@localhost mnt]# cat num.sh
#!/bin/bash
for NUM in $(seq 1 2 10)
do
echo $NUM
done
[root@localhost mnt]# sh num.sh
1
3
5
7
9
[root@localhost mnt]# vim exit.sh
[root@localhost mnt]# cat exit.sh
#!/bin/bash
for NAME in /etc/hello /etc/passwd /etc/group
do
ls -l $NAME &> /dev/null && echo $NAME is exit || echo $NAME is not exit
done
[root@localhost mnt]# sh exit.sh
/etc/hello is not exit
/etc/passwd is exit
/etc/group is exit
[root@localhost mnt]# vim exit.sh
[root@localhost mnt]# cat exit.sh
#!/bin/bash
for NAME in {1..5}
do
ping -c1 -w1 172.25.254.$NUM &> /dev/null && echo 172.25.254.$NUM is up || echo 172.25.254.$NUM down
done
[root@localhost mnt]# sh exit.sh
172.25.254. down
172.25.254. down
172.25.254. down
172.25.254. down
172.25.254. down
[root@localhost mnt]#
[root@localhost mnt]# vim userfile
[root@localhost mnt]# cat userfile
lee
westos
linux
loo
[root@localhost mnt]# vim passwdfile
[root@localhost mnt]# cat passwdfile
123
234
345
456
[root@localhost mnt]# vim createuser.sh
[root@localhost mnt]# cat createuser.sh
#!/bin/bash
COUNT=`wc -l /mnt/userfile | cut -d " " -f 1`
for NUM in $(seq 1 $COUNT)
do
USERNAME=`sed -n ${NUM}p $1`
PASSWD='sed -n ${NUM}p $2'
useradd $USERNAME
echo $PASSWD | passwd --stdin $USERNAME
done
[root@localhost mnt]# cp -p createuser.sh deluser.sh
[root@localhost mnt]# vim deluser.sh
[root@localhost mnt]# cat deluser.sh
#!/bin/bash
COUNT=`wc -l /mnt/userfile | cut -d " " -f 1`
for NUM in $(seq 1 $COUNT)
do
USERNAME=`sed -n ${NUM}p $1`
userdel $USERNAME
done
[root@localhost mnt]# cp -p deluser.sh iduser.sh
[root@localhost mnt]# vim iduser.sh
[root@localhost mnt]# cat iduser.sh
#!/bin/bash
COUNT=`wc -l /mnt/userfile | cut -d " " -f 1`
for NUM in $(seq 1 $COUNT)
do
USERNAME=`sed -n ${NUM}p $1`
id $USERNAME
done
[root@localhost mnt]# sh createuser.sh userfile passwdfile
Changing password for user lee.
passwd: all authentication tokens updated successfully.
Changing password for user westos.
passwd: all authentication tokens updated successfully.
Changing password for user linux.
passwd: all authentication tokens updated successfully.
Changing password for user loo.
passwd: all authentication tokens updated successfully.
[root@localhost mnt]# sh iduser.sh userfile
uid=1001(lee) gid=1001(lee) groups=1001(lee)
uid=1002(westos) gid=1002(westos) groups=1002(westos)
uid=1003(linux) gid=1003(linux) groups=1003(linux)
uid=1004(loo) gid=1004(loo) groups=1004(loo)
[root@localhost mnt]# sh deluser.sh userfile
[root@localhost mnt]# sh iduser.sh userfile
id: lee: no such user
id: westos: no such user
id: linux: no such user
id: loo: no such user
[root@localhost mnt]#
[root@localhost mnt]# a=1
[root@localhost mnt]# echo $a
1
[root@localhost mnt]# echo \$a
$a
[root@localhost mnt]# echo "$a"
1
[root@localhost mnt]# echo '$a'
$a
[root@localhost mnt]# echo $a $a $a
1 1 1
[root@localhost mnt]# echo \$a $a $a
$a 1 1
[root@localhost mnt]# echo '$a $a $a'
$a $a $a
[root@localhost mnt]# echo "$a $a $a"
1 1 1
[root@localhost mnt]# echo '$a0 $a $a'
$a0 $a $a
[root@localhost mnt]# echo ${a}0 \$a $a
10 $a 1
[root@localhost mnt]# echo * * * * *
createuser.sh deluser.sh exit.sh iduser.sh num.sh passwdfile show_ip.sh test.sh userfile createuser.sh deluser.sh exit.sh iduser.sh num.sh passwdfile show_ip.sh test.sh userfile createuser.sh deluser.sh exit.sh iduser.sh num.sh passwdfile show_ip.sh test.sh userfile createuser.sh deluser.sh exit.sh iduser.sh num.sh passwdfile show_ip.sh test.sh userfile createuser.sh deluser.sh exit.sh iduser.sh num.sh passwdfile show_ip.sh test.sh userfile
[root@localhost mnt]# echo "* * * * *"
* * * * *
[root@localhost mnt]# echo '* * * * *'
* * * * *
[root@localhost mnt]# echo "!"
-bash: !: event not found
[root@localhost mnt]# echo '!'
!
[root@localhost mnt]# echo "$"
$
[root@localhost mnt]# echo "$a"
1
[root@localhost mnt]# echo '$a'
$a
[root@localhost mnt]# echo "`"
> 1
> ^C
[root@localhost mnt]# echo '`'
`
[root@localhost mnt]# echo "\"
> a
> ^C
[root@localhost mnt]# echo '\'
\
[root@localhost mnt]# echo your hostname is `hostname`
your hostname is localhost.localdomain
[root@localhost mnt]# echo ***** your hostname is `hostname` *****
createuser.sh deluser.sh exit.sh iduser.sh num.sh passwdfile show_ip.sh test.sh userfile your hostname is localhost.localdomain createuser.sh deluser.sh exit.sh iduser.sh num.sh passwdfile show_ip.sh test.sh userfile
[root@localhost mnt]# echo '***** your hostname is `hostname` *****'
***** your hostname is `hostname` *****
[root@localhost mnt]# echo "***** your hostname is `hostname` *****"
***** your hostname is localhost.localdomain *****
[root@localhost mnt]# echo $[1+2]
3
[root@localhost mnt]# echo $[2+2]
4
[root@localhost mnt]# echo $[5*2]
10
[root@localhost mnt]# echo $[5**2]
25
[root@localhost mnt]# echo $[10/2]
5
[root@localhost mnt]# echo $[9%2]
1
[root@localhost mnt]# echo $[3%5]
3
[root@localhost mnt]# echo `expr 5 \+ 2`
7
[root@localhost mnt]# echo `expr 5 \- 2`
3
[root@localhost mnt]# echo `expr 5 \* 2`
10
[root@localhost mnt]# echo `expr 5 \/ 2`
2
[root@localhost mnt]# echo `expr 5 \% 2`
1
[root@localhost mnt]# let A=1+2
[root@localhost mnt]# echo $A
3
[root@localhost mnt]# let A=3-1
[root@localhost mnt]# echo $A
2
[root@localhost mnt]# let A=2*5
[root@localhost mnt]# echo $A
10
[root@localhost mnt]# let A=5%2
[root@localhost mnt]# echo $A
1
[root@localhost mnt]# let A=5/2
[root@localhost mnt]# echo $A
2
[root@localhost mnt]#
[root@localhost mnt]# ls
createuser.sh exit.sh num.sh show_ip.sh userfile
deluser.sh iduser.sh passwdfile test.sh
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# sh test.sh
1
2
3
4
5
[root@localhost mnt]# cat test.sh
#!/bin/bash
for ((i=1;i<=5;i++))
do
echo $i
done
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# cat test.sh
#!/bin/bash
for ((i=1;i<=5;i++))
do
echo $i
((i++))
done
[root@localhost mnt]# sh test.sh
1
3
5
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# cat test.sh
#!/bin/bash
for ((i=10;i>0;i--))
do
echo $i
((i--))
done
[root@localhost mnt]# sh test.sh
10
8
6
4
2
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# cat test.sh
#!/bin/bash
for ((i=1;i<10;i++))
do
((j+=i))
echo $j
done
[root@localhost mnt]# sh test.sh
1
3
6
10
15
21
28
36
45
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# cat test.sh
#!/bin/bash
for ((i=10;i>0;i--))
do
echo $i
sleep 1
done
[root@localhost mnt]# sh test.sh
10
9
8
7
6
5
4
3
2
1
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# cat test.sh
#!/bin/bash
for ((i=10;i>0;i--))
do
echo "After ${i}s is end"
sleep 1
done
[root@localhost mnt]# sh test.sh
After 10s is end
After 9s is end
After 8s is end
After 7s is end
After 6s is end
After 5s is end
After 4s is end
After 3s is end
After 2s is end
After 1s is end
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# cat test.sh
#!/bin/bash
for ((i=10;i>0;i--))
do
echo -ne "After ${i}s is end \r"
sleep 1
done
[root@localhost mnt]# sh test.sh
[root@localhost mnt]#
[root@localhost mnt]# ["1"="2"] && echo yes || echo no
-bash: [1=2]: command not found
no
[root@localhost mnt]# ["1" = "2"] && echo yes || echo no
-bash: [1: command not found
no
[root@localhost mnt]# [ "1" = "2" ] && echo yes || echo no
no
[root@localhost mnt]# [ "1" -lt "2" ] && echo yes || echo no
yes
[root@localhost mnt]# [ "1" -gt "2" ] && echo yes || echo no
no
[root@localhost mnt]# [ "1" -le "2" ] && echo yes || echo no
yes
[root@localhost mnt]# [ "1" -le "1" ] && echo yes || echo no
yes
[root@localhost mnt]# [ "1" -ge "2" ] && echo yes || echo no
no
[root@localhost mnt]# [ "1" -ne "2" ] && echo yes || echo no
yes
[root@localhost mnt]# [ "1" -eq "2" ] && echo yes || echo no
no
[root@localhost mnt]# [ "$a" -gt "0" -a "$a" -lt "10" ] && echo yes || echo no
yes
[root@localhost mnt]# a=100
[root@localhost mnt]# [ "$a" -gt "0" -a "$a" -lt "10" ] && echo yes || echo no
no
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# cat test.sh
#!/bin/bash
MIN=1
for ((i=3;i>0;i--))
do
while
[ "$i" -eq "0" -a "$MIN" -gt "0" ]
do
echo "After ${MIN}:${i} is end"
i=5
((MIN--))
done
echo "After ${MIN}:${i} is end"
sleep 1
done
[root@localhost mnt]# sh test.sh
After 1:3 is end
After 1:2 is end
After 1:1 is end
[root@localhost mnt]#