第十一单元 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
5)示例:
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# cat test.sh
#!/bin/bash -x
echo "Hello world!"
[root@localhost mnt]# sh test.sh
Hello world!
[root@localhost mnt]# bash test.sh
Hello world!
[root@localhost mnt]# chmod +x test.sh
[root@localhost mnt]# bash -x test.sh
+ echo 'Hello world!'
Hello world!
[root@localhost mnt]# ./test.sh
+ echo 'Hello world!'
Hello world!
[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
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"
4)示例
[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 *****
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
示例:
[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 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
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
示例:
[root@localhost mnt]# hostname
localhost.localdomain
[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
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
2)示例
[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
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
3)示例:
[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]# 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]#
9.示例:
[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
二、Bash位置参数
1.有两种简单的方法可以将用户输入读入bash中的变量。第一个方法是使用read提示用户输入(使用-p选项)并将其直接存储到一个或多个变量:交互式输入
# read -p 'Enter your first and last name: ' FIRST LAST
2.另一个方法是使用位置参数来读取传递给脚本的命令行参数或选项输入。各种特殊变量存储传递的选项编号Bash解析的个别参数或整个原始命令行。
指定的位置参数总数:$#
位置参数自身:$0、$1、$2、$3....
所有位置参数: $@、$*
3.示例:
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# cat test.sh
#!/bin/bash
echo $1
echo $2
echo $3
echo $*
echo $#
echo $@
[root@localhost mnt]# ./test.sh
0
[root@localhost mnt]# ./test.sh hello
hello
hello
1
hello
[root@localhost mnt]# ./test.sh hello world
hello
world
hello world
2
hello world
[root@localhost mnt]# ./test.sh hello world linux
hello
world
linux
hello world linux
3
hello world linux
[root@localhost mnt]#
[root@localhost mnt]# vim test.sh
[root@localhost mnt]# ./test.sh
Give me a world: hello linux world
hello linux world
[root@localhost mnt]# cat test.sh
#!/bin/bash
read -p "Give me a world: " HELLO
echo $HELLO
[root@localhost mnt]#
[root@localhost mnt]# vim id_check.sh
[root@localhost mnt]# cat id_check.sh
#!/bin/bash
read -p "Please input your name : " username
check=`getent passwd $username`
[ -n "$check" ] && (
echo "the user is exit"
) || (
read -p "Please input your passwd : " passwd
useradd $username
echo $passwd | passwd --stdin $username
)
[root@localhost mnt]# sh id_check.sh
Please input your name : student
the user is exit
[root@localhost mnt]# sh id_check.sh
Please input your name : linux
Please input your passwd : linux
Changing password for user linux.
passwd: all authentication tokens updated successfully.
[root@localhost mnt]# id linux
uid=1005(linux) gid=1005(linux) groups=1005(linux)
[root@localhost mnt]#
三、退出状态
1.Linux命令完成时,将返回退出状态。成功完成程序时,将返回0的推出状态。这被bash当作逻辑True值。非零退出状态通常表示发生了错误,并且被bash当作逻辑False值。
2.例如:grep的退出状态的含义:
0 – 在指定的文件中找到了模式
1 – 在指定的文件中未找到模式
>1 – 一些其他错误(无法打开文件、错误的搜索表达式等)
3.退出状态的值被存储在"?"中,可以使用以下命令查看:
# echo $?
四、test条件判断
1.test命令可用于评估bash脚本中的表达式。它评估其参数所指定的表达式,如果表达式为true,返回零退出状态,如果表达式为false,则返回非零退出状态。test具有替代语法,使用方括号"[]"将表达式括起来,这样更易于阅读。
2.语法:test EXPRESSION 或 [EXPRESSION]
1)非零或零长度字符串运算符:test -{n|z} STRING
[root@server0 ~]# [ -n westos ]; echo $?
0
[root@server0 ~]# [ -z westos ]; echo $?
1
2)字符串比较运算符:=、!=
[root@server0 ~]# [ abc = abc ]; echo $?
0
[root@server0 ~]# [ abc = ABC ]; echo $?
1
[root@server0 ~]# [ abc != ABC ]; echo $?
0
3)数字比较运算符:-eq、-ne、-lt、-le、-gt、-ge
[root@server0 ~]# [ 1 -eq 1 ]; echo $?
0
[root@server0 ~]# [ 1 -ne 1 ]; echo $?
1
[root@server0 ~]# [ 1 -gt 2 ]; echo $?
1
4)文件状态运算符:test -{b|c|e|f|d|r|w|x|s|L} FILE/DIRECTORY
[root@server0 ~]# [ -b /dev/sda ]; echo $?
1
[root@server0 ~]# [ -c /dev/zero ]; echo $?
0
[root@server0 ~]# [ -e /etc/passwd ]; echo $?
0
[root@server0 ~]# [ -f /etc/passwd ]; echo $?
0
[root@server0 ~]# [ -d /etc/passwd ]; echo $?
1
[root@server0 ~]# [ -L /etc/passwd ]; echo $?
1
5)二进制文件运算符:-ef、-nt、-ot
[root@server0 bin]# [ /bin/mount -ef /usr/bin/mount ]; echo $?
0
[root@server0 bin]# [ /bin/mount -nt /usr/bin/mount ]; echo $?
1
[root@server0 bin]# [ /bin/mount -ot /usr/bin/mount ]; echo $?
1
6)逻辑运算符:-o、-a、!、&&、||
[root@server0 bin]# [ 2 -gt 1 -a 1 -gt 2 ]; echo $?
1
[root@server0 bin]# [ 2 -gt 1 -o 1 -gt 2 ]; echo $?
0
[root@server0 bin]# [ ! 2 -gt 1 ]; echo $?
1
7)示例:
[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]#
[root@localhost mnt]# getent passwd user1
user1:x:1003:1003::/home/user1:/bin/bash
[root@localhost mnt]# getent passwd student
student:x:1000:1000:Student User:/home/student:/bin/bash
[root@localhost mnt]# CHECK=`getent passwd student`
[root@localhost mnt]# [ -n "$CHECK" ] && echo yes || echo no
yes
[root@localhost mnt]#
[root@localhost mnt]# vim ip_check.sh
[root@localhost mnt]# cat ip_check.sh
#!/bin/bash
ping -c1 -w1 $1 &> /dev/null && echo $1 is exit || echo $1 is not exit
[root@localhost mnt]# sh ip_check.sh 172.25.254.100
172.25.254.100 is exit
[root@localhost mnt]# sh ip_check.sh 172.25.254.242
172.25.254.242 is not exit
[root@localhost mnt]#
五、if语句
if命令检查if后面的命令或列表的退出值。如果第一个命令评估为true/零,则运行then之后的命令列表,直至任一else。如果第一个命令评估为false/非零,则运行else与fi之间的命令列表(反向平写if,标记if块的结束)。
语法:if command; then command; command2; else command3; fi
示例:
if test “$USER” != 'root' ; then
echo you are not logged in as root
fi
if [ $(id -u) -lt 9 ] ; then
echo “The number $(id -u) is less than 9!”
fi
www.westos.org
9if grep “^${USER}:” /etc/passwd &> /dev/null ; then
echo “${USER} is a local user on the system.”
else
echo “${USER} is not a local user.”
fi
systemctl is-active mariadb > /dev/null 2>&1 ; MARIADB_ACTIVE=$?
systemctl is-active postgresql > /dev/null 2>&1 ; POSTGRESQL_ACTIVE=$?
if [ $MARIADB_ACTIVE -eq 0 ];then
mysql
elif [ $POSTGRESQL_ACTIVE -eq 0 ];then
psql
else
sqlite3
fi
练习:
[root@localhost mnt]# vim createuser.sh
[root@localhost mnt]# cat createuser.sh
#!/bin/bash
if
[ -n "$1" -a -n "$2" ]
then
NUM1=`wc -l $1 | cut -d " " -f 1`
NUM2=`wc -l $2 | cut -d " " -f 1`
if
[ "$NUM1" -eq "$NUM2" ]
then
for NUM in `seq 1 $NUM1`
do
USERNAME=`sed -n ${NUM}p $1`
PASSWD=`sed -n ${NUM}p $2`
CHECK=`getent passwd $USERNAME`
if
[ -z "$CHECK" ]
then
useradd $USERNAME
echo $PASSWD | passwd --stdin $USERNAME
else
echo "The $USERNAME is exist"
fi
done
else
echo "error:$1's line is different $2,Please check $1 or $2"
fi
else
echo "error:Please give me username file and passwd file!!!"
fi
[root@localhost mnt]# vim userfile
[root@localhost mnt]# cat userfile
username1
username2
username3
username4
username5
username6
username7
username8
[root@localhost mnt]# vim passfile
[root@localhost mnt]# cat passfile
password1
password2
password3
password4
password5
password6
password7
password8
[root@localhost mnt]# sh createuser.sh
error:Please give me username file and passwd file!!!
[root@localhost mnt]# sh createuser.sh userfile passfile
The username1 is exist
The username2 is exist
The username3 is exist
The username4 is exist
The username5 is exist
The username6 is exist
The username7 is exist
The username8 is exist
[root@localhost mnt]# userdel -r username1
[root@localhost mnt]# userdel -r username2
[root@localhost mnt]# userdel -r username3
[root@localhost mnt]# userdel -r username4
[root@localhost mnt]# sh createuser.sh userfile passfile
Changing password for user username1.
passwd: all authentication tokens updated successfully.
Changing password for user username2.
passwd: all authentication tokens updated successfully.
Changing password for user username3.
passwd: all authentication tokens updated successfully.
Changing password for user username4.
passwd: all authentication tokens updated successfully.
The username5 is exist
The username6 is exist
The username7 is exist
The username8 is exist
[root@localhost mnt]#
[root@localhost mnt]# vim check_num.sh
[root@localhost mnt]# cat check_num.sh
#!/bin/bash
A=10
B=0
if
[ -n "$1" ]
then
if
[ "$1" -le "$A" -a "$1" -ge "$B" ]
then
echo ${1}属于0-10
else
echo ${1}不属于0-10
fi
else
echo "ERROR:give me a num!!!"
fi
[root@localhost mnt]# sh check_num.sh
ERROR:give me a num!!!
[root@localhost mnt]# sh check_num.sh 1
1属于0-10
[root@localhost mnt]# sh check_num.sh -7
-7不属于0-10
[root@localhost mnt]# sh check_num.sh 17
17不属于0-10
[root@localhost mnt]#
六、case语句
case语句 :它能够把变量的内容与多个模板进行匹配,再根据成功匹配的模板去决定应该执行哪部分代码。
case "$1" in
start)
systemctl start $2
;;
stop)
systemctl stop $2
;;
reload|restart)
systemctl stop $2
systemctl start $2
;;
*)
echo "Usage: $0 (start|stop|restart|reload)"
;;
esac
示例:
[root@localhost mnt]# vim case_file.sh
[root@localhost mnt]# cat case_file.sh
#!/bin/bash
case "$1" in
-b)
if
[ -b "$2" ]
then
echo "$2 is a block"
else
echo "$2 is not a block"
fi
;;
-f)
if
[ -f "$2" ]
then
echo "$2 is a file"
else
echo "$2 is not a file"
fi
;;
-d)
if
[ -d "$2" ]
then
echo "$2 is a dir"
else
echo "$2 is not a dir"
fi
;;
*)
echo "I Don't Know"
;;
esac
[root@localhost mnt]# sh case_file.sh
I Don't Know
[root@localhost mnt]# sh case_file.sh -d
is not a dir
[root@localhost mnt]# sh case_file.sh -d /etc/
/etc/ is a dir
[root@localhost mnt]# sh case_file.sh -d /etc/passwd
/etc/passwd is not a dir
[root@localhost mnt]# sh case_file.sh -f /etc/passwd
/etc/passwd is a file
[root@localhost mnt]# sh case_file.sh -b /dev/vda1
/dev/vda1 is a block
[root@localhost mnt]#
七、expect语句
在shell中利用expect实现自动应答脚本。
# cat talk
echo "who are you?"
read who
echo "hello, $who"
echo "are you
happy?"
read answer
echo "why?"
read answer
# cat auto
#!/usr/bin/expect
#set timeout 10
spawn ./talk
expect "who"
send "firefly\n"
expect "happy?"
send "Yes,I am happy.\n"
expect "why?"
send "任性!\n"
expect eof
exit
1)#!/usr/bin/expect
这一行告诉操作系统脚本里的代码使用那一个shell来执行。
2)set timeout 10
设置后面所有的expect命令的等待响应的超时时间,单位为秒。
3)spawn talk
spawn是expect的内部命令,作用是给后面的shell指令加个壳,用来传递交互指令。
4)expect "who"
判断上次输出结果里是否包含“who”的字符串,如果有则立即返回,否则等待超时时间后返回。
5)send "westos\n"
执行交互动作,相当于手工输入"westos"。
6)expect eof
作用是在输出中搜索文件结束符,如果没有这一行,脚本会立即退出,得不到正确结果。
7)interact
执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。否则退出登录。
8)$argv 参数数组
expect脚本可以接受从bash传递过来的参数.可以使用[lindex $argv n]获得,n从0开始,分别表示第一个,第二个,第三个....参数。
9)示例:
[root@localhost mnt]# vim 233.exp
[root@localhost mnt]# cat 233.exp
#!/usr/bin/expect
spawn ssh root@172.25.254.42
expect {
"(yes/no)?" {send "yes\r";exp_continue};
"password:" {send "westos\r"};
}
interact
[root@localhost mnt]# chmod +x 233.exp
[root@localhost mnt]# ./233.exp
spawn ssh root@172.25.254.42
The authenticity of host '172.25.254.42 (172.25.254.42)' can't be established.
ECDSA key fingerprint is f2:5e:9f:f4:87:12:4b:10:7a:42:16:1f:a0:3a:9a:53.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.25.254.42' (ECDSA) to the list of known hosts.
root@172.25.254.42's password:
Last login: Wed Apr 26 15:51:51 2017
[root@foundation42 ~]#
八、环境变量
1.shell和脚本使用变量来存储数据 ,有些变量可以连同它们的内容传递给子进程,这些变量我们称之为环境变量。
[root@server0 ~]# LINUX=redhat
[root@server0 ~]# echo $LINUX
redhat
[root@server0 ~]# bash
[root@server0 ~]# echo $LINUX
[root@server0 ~]# exit
exit
[root@server0 ~]# export LINUX
[root@server0 ~]# bash
[root@server0 ~]# echo $LINUX
redhat
[root@server0 ~]# exit
exit
使用env命令显示所有环境变量
使用set命令现实所有本地定义的shell变量
2.Bash启动脚本
在用户登录的时候,会运行全局变量文件/etc/profile,和用户自定义变量文件
~/.bash_profile去初始化它们的环境变量。
/etc/profile
\_ /etc/profile.d/*.sh
~/.bash_profile
\_ ~/.bashrc
\_ /etc/bashrc
3.使用别名
alias命令可以用来自定义属于自己的系统命令,写入~/.bashrc 文件永久生效。
1)查看别名:
# alias
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
...
2)设置别名:
# alias mycom='echo hello;hostname'
# mycomm
hello
server0.example.com
3)删除别名:
unalias mycomm
4.使用函数
pathmunge () {
if [ "$2" = "after" ] ; then
PATH=$PATH:$1
else
PATH=$1:$PATH
fi
}
...
if [ "$EUID" = "0" ]; then
pathmunge /usr/sbin
pathmunge /usr/local/sbin
else
pathmunge /usr/local/sbin after
pathmunge /usr/sbin after
fi
5.示例:
[root@localhost mnt]# LINUX=redhat
[root@localhost mnt]# echo $LINUX
redhat
[root@localhost mnt]# bash
[root@localhost mnt]# echo $LINUX
[root@localhost mnt]# exit
exit
[root@localhost mnt]# export LINUX
[root@localhost mnt]# bash
[root@localhost mnt]# echo $LINUX
redhat
[root@localhost mnt]# exit
exit
[root@localhost mnt]# echo $LINUX
redhat
[root@localhost mnt]# bash
[root@localhost mnt]# echo $LINUX
redhat
[root@localhost mnt]# exit
exit
[root@localhost mnt]# vim /etc/profile
[root@localhost mnt]# cd
[root@localhost ~]# vim .bash_profile
[root@localhost ~]# alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
[root@localhost ~]# alias mycom='echo hello;hostname'
[root@localhost ~]# mycom
hello
localhost
[root@localhost ~]# unalias mycom
[root@localhost ~]# mycom
bash: mycom: command not found...
[root@localhost ~]#