3unit12
Red Hat System Administration III
####################################单元 十二Bash脚本条件判断和控制流结构
###################Bash位置参数
有两种简单的方法可以将用户输入读入bash中的变量。
第一个方法是使用read提示用户输入(使用-p选项)并将其直接存储到一个或多个变量:
交互式输入
# read -p 'Enter your first and last name: ' FIRST LAST
另一个方法是使用位置参数来读取传递给脚本的命令行参数或选项输入。各种特殊变量存储传递的选项编号
Bash解析的个别参数或整个原始命令行。
指定的位置参数总数:$#
位置参数自身:$0、$1、$2、$3....
所有位置参数: $@、$*
eg:
[root@mail-eastos mnt]# vim test.sh
1 #!/bin/bash
2 echo $1
3 echo $2
4 echo $3
5 echo $*
6 echo $#
7 echo $@
[root@mail-eastos mnt]# chmod +x test.sh
[root@mail-eastos mnt]# ./test.sh hello linux redhat
hello
linux
redhat
hello linux redhat
3
hello linux redhat
###################退出状态
Linux命令完成时,将返回退出状态。成功完成程序时,将返回0的推出状态。这被bash当作逻辑True值。非零退出状态通常表示发生了错误,并且被bash当作逻辑False值。
例如:grep的退出状态的含义:
0 – 在指定的文件中找到了模式
1 – 在指定的文件中未找到模式
>1 – 一些其他错误(无法打开文件、错误的搜索表达式等)
推出状态的值被存储在"?"中,可以使用以下命令查看:
# echo $?
#####################test条件判断
test命令可用于评估bash脚本中的表达式。它评估其参数所指定的表达式,如果表达式为true,返回零退出状态,如果表达式为false,则返回非零退出状态。test具有替代语法,使用方括号"[]"将表达式括起来,这样更易于阅读。
语法:test EXPRESSION 或 [EXPRESSION] 【】man test
非零或零长度字符串运算符:test -{n|z} STRING
[root@server0 ~]# [ -n westos ]; echo $?
0
[root@server0 ~]# [ -z westos ]; echo $?
1
字符串比较运算符:=、!=
[root@server0 ~]# [ abc = abc ]; echo $?
0
[root@server0 ~]# [ abc = ABC ]; echo $?
1
[root@server0 ~]# [ abc != ABC ]; echo $?
0
数字比较运算符:-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
文件状态运算符: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
eg:检查文件状态脚本
[root@mail-eastos mnt]# vim check_file.sh
#!/bin/bash
2 CHECK () {
3 if
4 [ $1 $2 ]
5 then
6 echo $2 is a $3
7 else
8 echo $2 is not a $3
9 fi
10 }
11 case "$1" in
12 -f)
13 CHECK -f $2 file
14 ;;
15 -b)
16 CHECK -b $2 block
17 ;;
18 -d)
19 CHECK -d $2 directory
20 ;;
21 *)
22 echo "ERROR:please input a argment and file after command"
23 esac
二进制文件运算符:-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
逻辑运算符:-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
[root@mail-eastos mnt]# sh check_file.sh -f /etc/passwd
/etc/passwd is a file
[root@mail-eastos mnt]# sh check_file.sh -f /etc/
/etc/ is not a file
[root@mail-eastos mnt]# sh check_file.sh -d /etc/
/etc/ is a directory
eg:
[root@mail-eastos mnt]# a=1
[root@mail-eastos mnt]# b=1
[root@mail-eastos mnt]# test "$a" = "$b" &&echo yes
yes
[root@mail-eastos mnt]# [ "$a" = "$b" ]&&echo yes
yes
[root@mail-eastos mnt]# sdAD
bash: sdAD: 未找到命令...
[root@mail-eastos mnt]# echo $?
127
[root@mail-eastos mnt]# ls
check_ip.sh create_user.sh db.sh test.sh
check_num.sh create_users.sh passfile userfile
[root@mail-eastos mnt]# echo $?
0
[root@mail-eastos mnt]# [ 1 -ge 1 ];echo $?
0
#############################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
if 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
###########################################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
#########################################################expect语句
[root@localhost mnt]# yum install expect
在shell中利用expect实现自动应答脚本。
# cat talk # cat auto
echo "who are you?" #!/usr/bin/expect
read who #set timeout 10
echo "hello, $who" spawn ./talk
echo "are you expect "who"
happy?" send "firefly\n"
read answer expect "happy?"
echo "why?" send "Yes,I am happy.\n"
read answer expect "why?"
send "任性!\n"
expect eof
exit
[root@localhost mnt]# which expect
/usr/bin/expect
eg:
[root@localhost mnt]# vim ask.sh
#!/bin/bash
2 read -p "input your name :" NAME
3 read -p "input your age :" AGE
4 read -p "input your class :" CLASS
5 read -p "input your feel :" FELL
6 echo $NAME is $AGE\'s old and $NAME is $CLASS student fell $FELL
[root@localhost mnt]# vim answer.exp
#!/usr/bin/expect
2 spawn /mnt/ask.sh
3 expect {
4 "name :" {send "yy\r";exp_continue};
5 "age :" {send "12\r";exp_continue};
6 "class :" {send "linux\r";exp_continue};
7 "feel :" {send "happy\r"};
8 }
9 expect eof ##退出会话
这一行告诉操作系统脚本里的代码使用那一个shell来执行。
set timeout 10
设置后面所有的expect命令的等待响应的超时时间,单位为秒。
spawn talk
spawn是expect的内部命令,作用是给后面的shell指令加个壳,用来传递交互指令。
expect "who"
判断上次输出结果里是否包含“who”的字符串,如果有则立即返回,否则等待超时时间后返回。
send "westos\n"
执行交互动作,相当于手工输入"westos"。
expect eof
作用是在输出中搜索文件结束符,如果没有这一行,脚本会立即退出,得不到正确结果。
interact
执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。否则退出登录。
$argv 参数数组
expect脚本可以接受从bash传递过来的参数.可以使用[lindex $argv n]获得,n从0开始,分别表示第
一个,第二个,第三个....参数。
eg:自动连接
[root@localhost mnt]# vim auto_ssh.exp
#!/usr/bin/expect
2 spawn ssh root@172.25.254.241
3 expect {
4 "(yes/no)?" {send "yes\r";exp_continue};
5 "password:" {send "redhat\r"};
6 }
7 interact ##停留在会话中
[root@localhost mnt]# /mnt/auto_ssh.exp | grep -E "spawn|password" -v
localhost
##########################################环境变量
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变量
Bash启动脚本
在用户登录的时候,会运行全局变量文件/etc/profile,和用户自定义变量文件
~/.bash_profile去初始化它们的环境变量。
/etc/profile
\_ /etc/profile.d/*.sh
~/.bash_profile
\_ ~/.bashrc
\_ /etc/bashrc
使用别名
alias命令可以用来自定义属于自己的系统命令,写入~/.bashrc 文件永久生效。
查看别名:
# alias
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
...
设置别名:
# alias mycom='echo hello;hostname'
# mycomm
hello
server0.example.com
删除别名: unalias mycomm
eg:
[root@localhost ~]# vim .bashrc ##局部
[root@localhost ~]# source .bashrc
[root@localhost ~]# vim /etc/bashrc ##全局
[root@localhost ~]# source /etc/bashrc
使用函数
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
eg:
[root@localhost mnt]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@localhost mnt]# which ls
alias ls='ls --color=auto'
/usr/bin/ls
[root@localhost mnt]# PATH=$PATH:/mnt
[root@localhost mnt]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/mnt
[root@localhost mnt]# ask.sh
[root@localhost mnt]# logout
Connection to 172.25.254.141 closed.
[root@foundation60 ~]# ssh root@172.25.254.141
root@172.25.254.141's password:
Last login: Mon May 1 06:57:21 2017 from 172.25.254.60
[root@localhost ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@localhost ~]# a=1
[root@localhost ~]# echo $a
1
[root@localhost ~]# bash
[root@localhost ~]# echo $a
[root@localhost ~]# export a=1
[root@localhost ~]# bash
[root@localhost ~]# echo $a
1
Connection to 172.25.254.141 closed.
[root@foundation60 ~]# ssh root@172.25.254.141
root@172.25.254.141's password:
Last login: Mon May 1 07:12:51 2017 from 172.25.254.60
[root@localhost ~]# echo $a
[root@localhost ~]# su - student
[student@localhost ~]$ echo $a
[student@localhost ~]$ vim .bash_profile ##局部变量
[student@localhost ~]$ echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/student/.local/bin:/home/student/bin
[student@localhost ~]$ source .bash_profile
[student@localhost ~]$ echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/student/.local/bin:/home/student/bin:/home/student/.local/bin:/home/student/bin:/mnt
[student@localhost ~]$ exit
logout
[root@localhost ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@localhost ~]# vim /etc/profile ##全局变量
[root@localhost ~]# source /etc/profile
eg:
#!/bin/bash
2 read -p "Give me a world :" HELLO
3 echo $HELLO
eg:检查指定ip的主机是否开机
[root@mail-eastos mnt]# vim check_ip.sh
1 #!/bin/bash
2 read -p "please input your ip :" A
3 ping $A -c1 -w1 &>/dev/null && echo $A is up ||echo $A is down
eg:自动创建用户脚本 ##文本行不一样,文件所加个数缺少,用户存在报错
[root@mail-eastos mnt]# vim userfile
[root@mail-eastos mnt]# vim passfile
[root@mail-eastos mnt]# vim create_user.sh
#!/bin/bash
2 MAX=`wc -l $1|cut -d " " -f 1`
3 MAX1=`wc -l $2|cut -d " " -f 1`
4 CHECK=`getent passwd $1`
5 if
6 [ "$MAX" -ne "$MAX1" ]
7 then
8 echo error
9 elif
10 [ -n "$CHECK"]
11 then
12 echo error
13 elif
14 else
15 for NUM in $(seq 1 $MAX)
16 do
17 NAME=`sed -n ${NUM}p $1`
18 PASSWORD=`sed -n ${NUM}p $2`
19 useradd $NAME
20 echo $PASSWORD |passwd --stdin $NAME
21 done
22 fi
eg:检测10以内的数字脚本
[root@mail-eastos mnt]# vim check_num.sh
#!/bin/bash
2 if
3 [ -n "$1" ]
4 then
5 if
6 [ "$1" -lt "10" -a "$1" -gt "0" ]
7 then
8 echo "属于0-10"
9 else
10 echo "不属于0-10"
11 fi
12 else
13 echo "please give me a num:"
14 fi
eg:数据库备份脚本
[root@mail-eastos mnt]# vim db.sh
#!/bin/bash
2 for DB in $(mysql -e "show databases;" -E -N | grep -v '^*' |gre p -v 'schema$')
3 do
4 echo "Backing up $DB"
5 mysqldump $DB >/dbbackup/$DB.dump
6 done
7 echo ""
8 for DBDUMP in /dbbackup/*
9 do
10 SIZE=$(stat--printf"%s\n"$DBDUMP)
11 echo "$DBDUMP $SIZE"
12 done
eg:自动添加分区脚本
[root@localhost mnt]# vim fdisk_add.sh
1 #!/bin/bash
2 fdisk $1 <<end
3 n
4
5
6
7 +100M
8 wq
9 end
[root@localhost mnt]# sh fdisk_add.sh /dev/vdb