Linux脚本基础学习二

来源:互联网 发布:怎么查非洲的市场数据 编辑:程序博客网 时间:2024/06/03 20:35



Bash脚本条件判断和控制流结构

1.Bash位置参数和退出状态 条件判断和控制流结构

2.Bash位置参数
有两种简单的方法可以将用户输入读入bash中的变量。第一个方法是使用read提示用户输入(使用-p选项)并将其直接存储到一个或多个变量:
交互式输入
# read -p 'Enter your first and last name: ' FIRST LAST
另一个方法是使用位置参数来读取传递给脚本的命令行参数或选项输入。各种特殊变量存储传递的选项编号
Bash解析的个别参数或整个原始命令行。
指定的位置参数总数:$#
位置参数自身:$0、$1、$2、$3....
所有位置参数: $@、$*
[root@localhost mnt]# vim test.sh
#!/bin/bash
read -p "please give me a address: " a  ##a在这里是一个变量,指定执行脚本时输入的ip
ping -c1 -w1 $a &> /dev/null && echo $a is up || echo $a is down ##ping命令判断该ip主机网络是否通着
[root@localhost mnt]# sh test.sh
please give me a address: 172.25.254.6
172.25.254.6 is up

3.退出状态
Linux命令完成时,将返回退出状态。成功完成程序时,将返回0的推出状态。这被bash当作逻辑True值。非0退出状态通常表示发生了错误,并且被bash当作逻辑False值。
例如:grep的退出状态的含义:
0 – 在指定的文件中找到了模式
1 – 在指定的文件中未找到模式
>1 – 一些其他错误(无法打开文件、错误的搜索表达式等)
出状态的值被存储在"?"中,可以使用以下命令查看:
# echo $?
[root@localhost mnt]# ls /mnt  ##执行正确的命令,该状态本存储在?中
test.sh
[root@localhost mnt]# echo $?  ##执行该命令输出为0表示上条命令没有报错
0
[root@localhost mnt]# lf /mnt
bash: lf: command not found...
[root@localhost mnt]# echo $?  ##不为0表示上条命令执行出错
127

4.test条件判断
test命令可用于评估bash脚本中的表达式。它评估其参数所指定的表达式,如果表达式为true,返回零退出状态,如果表达式为false,则返回非零退出状态。
语法:test EXPRESSION 或 [EXPRESSION]
非零或零长度字符串运算符:test -{n|z} STRING
[root@localhost mnt]# a=3   ##给a赋值
[root@localhost mnt]# test -n "$a" ;echo $? ##test -n "$a"表示判断a的值是否存在,存在则该表达时正确,用echo $?判断前一个命令没有错误输入,所以脚本产生的结果为0
0
[root@localhost mnt]# test -z "$a" ;echo $? ##-z表示a的值不存在时是正确输出,此时a的值存在,因此echo $?判断结果为1,表示上条命令为错误输出
1
[root@localhost mnt]# test -z "$b" ;echo $?
0
[root@localhost mnt]# test -n "$b" ;echo $?
1


test具有替代语法,使用方括号"[]"将表达式括起来,这样更易于阅读。
[root@localhost mnt]# [ -n a ]; echo $? ##该命令效果与test -n "$a" ;echo $?相同,"[]"将表达式括起来
0
[root@localhost mnt]# [ -z a ]; echo $? ##该命令效果与test -z "$a" ;echo $?相同,"[]"将表达式括起来
1
[root@localhost mnt]# [ -n b ]; echo $?
0
[root@localhost mnt]# [ -z b ]; echo $?
1


5.字符串比较运算符:=、!=
[root@localhost mnt]# [ westos = westos ]; echo $? ##"="表示等于,"!="表示不相等
0
[root@localhost mnt]# [ westos = Westos ]; echo $?
1
[root@localhost mnt]# [ westos != Westos ]; echo $?
0

[root@localhost mnt]# a=1  ##给a赋值1
[root@localhost mnt]# b=1  ##给b赋值1
[root@localhost mnt]# [ "$a" = "$b" ] && echo yes || echo no ##当a等于b时,输出yes,否则输出no
yes
[root@localhost mnt]# [ "$a" != "$b" ] && echo yes || echo no ##当a不等于b时,输出yes,否则输出no
no
[root@localhost mnt]# b=2
[root@localhost mnt]# [ "$a" = "$b" ] && echo yes || echo no
no
[root@localhost mnt]# [ "$a" != "$b" ] && echo yes || echo no
yes
[root@localhost mnt]# [ ! "$a" = "$b" ] && echo yes || echo no ##当a不等于b时,输出yes,否则输出no
yes

数字比较运算符:-eq、-ne、-lt、-le、-gt、-ge
-le 小于等于
-lt 小于
-gt 大于
-ge 大于等于
-ne 不等于

[root@localhost mnt]# [ 3 -le 4 ]; echo $? ##3小于等于,正确,输出0
0
[root@localhost mnt]# [ 3 -lt 4 ]; echo $? ##3小于4,正确,输出0
0
[root@localhost mnt]# [ 5 -lt 4 ]; echo $? ##5小于4,错误,输出1
1
[root@localhost mnt]# [ 5 -gt 4 ]; echo $? ##5大于4,正确,输出0
0
[root@localhost mnt]# [ 5 -ge 4 ]; echo $? ##5大于等于4,正确,输出0
0
[root@localhost mnt]# [ 5 -ne 4 ]; echo $? ##5不等于4,正确,输出0
0
[root@localhost mnt]# [ 4 -ne 4 ]; echo $? ##4不等于4,错误,输出1
1

脚本示例
实现判断网络通不通
[root@localhot mnt]# vim test.sh
#!/bin/bash
if
        [ ! "$#" -eq "1" ]  ##-eq表示相等,前面加!表示不相等,$#表示脚本后面跟的字符
        then
        echo "please give me a address"
        else
        for IP in $1
        do ping -c1 -w1 $1 &> /dev/null && echo $1 is up || echo $1 is down
        done
fi
[root@localhost mnt]# sh test.sh 172.25.254.6
172.25.254.6 is up


脚本示例
实现判断两个数字相加大于10

[root@localhost mnt]# vim check_num.sh
#!/bin/bash
while
[ -z "$1" -o -z "$2" ]  ##-z判断$1,$2是否存在,表示$1或者$2不存在时
do
echo "please give me two num after check_num.sh" ##执行此处内容
exit 1       ##exit1表示退出
done
((NUM=$1+$2))      ##$1+$2的值赋给NUM
[ "$NUM" -lt "10" ] && echo "$1+$2 is smaller than 10" || echo "$1+$2 is bigger than 10" 
##表示当NUM的值小于10时,输出$1+$2 is smaller than 10,否则输出$1+$2 is bigger than 10
执行效果
[root@localhost mnt]# sh check_num.sh
please give me two num after check_num.sh
[root@localhost mnt]# sh check_num.sh 23 44
23+44 is bigger than 10
[root@localhost mnt]# sh check_num.sh 2 3
2+3 is smaller than 10

6.文件状态运算符:test -{b|c|e|f|d|r|w|x|s|L} FILE/DIRECTORY
-b 块型
-c 字符型
-e 判断文件是否存在
-f 文件型
-d 目录
-x 可执行
-s 是否为空
-L/-h 软链接
-S 嵌套文件
[root@localhost mnt]# [ -b "/dev/vdb" ] && echo yes || echo no ##-b 判断是否是块,是输出yes
yes         
[root@localhost mnt]# [ -c "/dev/pts/0" ]&& echo yes || echo no ##-c 判断是否为字符型
yes
[root@localhost mnt]# [ -e "/mnt" ]&& echo yes || echo no ##-e 判断是否存在
yes
[root@localhost mnt]# [ -f "/mnt/test.sh" ]&& echo yes || echo no##-f 判断是否是文件型
yes
[root@localhost mnt]# [ -d "/etc" ]&& echo yes || echo no ##-d 判断是否为目录
yes
[root@localhost mnt]# [ -x "/mnt/test.sh" ]&& echo yes || echo no##-x 判断是否可执行
yes
[root@localhost mnt]# touch file
[root@localhost mnt]# [ -s "/mnt/file" ]&& echo yes || echo no ##-s 判断是否不为空
no
[root@localhost mnt]# [ -S "/var/lib/mysql/mysql.sock" ] && echo yes || echo no ##-S 判断是否为嵌套文件
yes

脚本示例
实现判断为文件是否存在并判断类型

[root@localhost mnt]# vim check_file.sh
#!/bin/bash
while [ -z "$*" ]
do
        echo "please input a filename"
        exit 1
done
[ -e $1 ] || (echo $1 is not exist;exit 1) ##-e 判断是否存在,此句表示当$1不存在时,输出$1 is not exist,并直接退出
[ -b $1 ] && echo "$1 is a block"  ##-b 判断是否为块文件
[ -c $1 ] && echo "$1 is a character file" ##-c 判断是否为字符型文件
[ -f $1 ] && echo "$1 is a file"  ##-f 判断是否为文件
[ -d $1 ] && echo "$1 is a directory"  ##-d 判断是否为目录
[ -S $1 ] && echo "$1 is a socket"  ##-S 判断是否为嵌套文件
[ -L $1 ] && echo "$1 is a soft link  ##-L 判断是否为软链接
[root@localhost mnt]# sh check_file.sh  /mnt
/mnt is a directory
[root@localhost mnt]# sh check_file.sh  /var/lib/mysql/mysql.sock
/var/lib/mysql/mysql.sock is a socket
[root@localhost mnt]# sh check_file.sh  /mnt/file
/mnt/file is a file
[root@localhost mnt]# sh check_file.sh  /mnt/file1
/mnt/file1 is not exist
[root@localhost mnt]# sh check_file.sh  /dev/vdb
/dev/vdb is a block

7.二进制文件运算符:-ef、-nt、-ot
[ 1 -ef 2 ] 1和2互为硬链接
[ 1 -nt 2 ] 1比2新
[ 1 -ot 2 ] 1比2旧
[root@localhost mnt]# [ /bin/mount -ef /usr/bin/mount ] && echo yes || echo no 
yes      ##/bin/mount 和/usr/bin/mount互为硬链接
[root@localhost mnt]# touch test
[root@localhost mnt]# [ /mnt/file -nt /mnt/test ] && echo yes ||echo no 
no      ##/mnt/file 比 /mnt/test 旧
[root@localhost mnt]# [ /mnt/file -ot /mnt/test ] && echo yes ||echo no
yes      ##/mnt/file 比 /mnt/test 旧
逻辑运算符:-o、-a、!、&&、||
[ a -o b ] ##条件a或者条件b成立
[ a -a b ] ##条件a和条件b都成立
[ ! a ]  ##条件a不成立
[ a ] && 1 || 2 ##当条件a成立时,执行1,否则执行2
[root@localhost mnt]# [ 2 -gt 1 -o 2 -lt 1 ] && echo yes || echo no ##当2大于1成立或者2小于1成立时,输出yes
yes
[root@localhost mnt]# [ 2 -gt 1 -a 2 -lt 1 ] && echo yes || echo no ##当2大于1成立并且2小于1成立时,输出yes
no

 
8.if语句
if命令检查if后面的命令或列表的退出值。如果第一个命令评估为true/零,则运行then之后的命令列表,直至任一else。如果第一个命令评估为false/非零,则运行else与fi之间的命令列表(反向平写if,标记if块的结束)。
语法:if command; then command; command2; else command3; fi

脚本示例
eg1 实现自动建立文件写入的用户密码设置为westos,如果用户存在则不做任何操作

[root@localhost mnt]# vim create_user.sh
#!/bin/bash      ##如果if后面的条件成立,则执行then后面的命令,否则直接进入else
if
[ -z "$*" ]      ##判断脚本后面的字符是否不存在
then       ##如不存在则执行then后面的命令
        echo "USE: /mnt/create_user /mnt/userfile"
else       ##否则执行else后面的命令
for NUM in $(seq 1 `wc -l $* | cut  -d " " -f 1`)      ##将$1中的行数赋值给NUM
do      NAME=`sed -n ${NUM}p $*`                      ##将$1中的内容一行一行赋给变量NAME
        id $NAME &>/dev/null                                 ##用id命令判断用户是否存在
        if [ "$?" = "0" ]                                                 ##如果$?=0成立即用户存在则输出$NAME is exist
        then echo $NAME is exist
        else `useradd $NAME`                                 ##否则执行建立用户
        `echo westos | passwd --stdin $NAME` &>/dev/null       ##设定密码为westos
        fi
done
fi


[root@localhost mnt]# chmod +x create_user.sh
[root@localhost mnt]# vim userfile
user1
user2
user3
[root@localhost mnt]# sh create_user.sh
USE: /mnt/create_user /mnt/userfile
[root@localhost mnt]# sh create_user.sh userfile
[root@localhost mnt]# id user1
uid=1001(user1) gid=1001(user1) groups=1001(user1)

eg2 实现自动建立文件写入的用户密码设置为westos,如果用户存在则不做任何操作
[root@localhost mnt]# vim create_user1.sh
#!/bin/bash
if      [ -z "$1" ]
then    echo please give me a userfile
elif    [ ! -e "$1" ]
then    echo "$1 is not exist"
else
        for NAME in `cat $1`
        do
                USER=`getent passwd $NAME`  ##用getent命令判断用户是否存在
                if      [ -z "$USER" ]
                then    useradd $NAME
                        echo westos | passwd --stdin $NAME
                else    echo $NAME is exist
                fi
        done
fi

[root@localhost mnt]# sh create_user1.sh userfile1
Changing password for user user4.
passwd: all authentication tokens updated successfully.
Changing password for user user5.
passwd: all authentication tokens updated successfully.
Changing password for user user6.
passwd: all authentication tokens updated successfully.


eg3 脚本控制自动建立删除用户
[root@localhost mnt]# vim ctrl_user.sh
#!/bin/bash
if     
[ "$1" = "create" ]     ##$1表示脚本后第一个字符,当$1=create即表示要建立用户
then       ##如果上述条件成立,则读then包含的命令,如果不成立则进入elif
        if      ##当$1=create时要做的动作
                [ -z "$2" ]    ##判断$2是否为空,如果为空则执行then,否则进入elif
        then
                echo please give me a userfile  ##$2为空时,执行此命令
        elif
                [ ! -e "$2" ]    ##$2不为空时,判断$2是否存在,如果不存在执行then如果存在进入else
        then
                echo "$2 is not exist"   
        else
                for NAME in `cat $2`   ##for,do,done语句建立用户
                do     
                        USER=`getent passwd $NAME`
                if
                        [ -z "$USER" ]
                then
                        useradd $NAME
                        echo westos | passwd --stdin $NAME
                else
                        echo $NAME is exist
                fi
                done
        fi
elif       ##当$1=delete时要做的动作
[ "$1" = "delete" ]
then
        if
                [ -z "$2" ]
        then
                echo please give me a userfile
        elif
                [ ! -e "$2" ]
        then
                echo "$2 is not exist"
        else
                for NAME in `cat $2`
                do
                        USER=`getent passwd $NAME`
                if
                        [ ! -z "$USER" ]
                then
                        userdel -r $NAME
                else
                        echo $NAME is not exist
                fi
                done
        fi
else      ##当$1,$2既不是create,又不是delete是执行此命令
        echo "Useage:ctrl_user.sh <create|delete> <userfile>"
fi      ##每一个if语句都要以fi结束


[root@localhost mnt]# chmod +x ctrl_user.sh s
[root@localhost mnt]# sh ctrl_user.sh
Useage:ctrl_user.sh <create|delete> <userfile>
[root@localhost mnt]# sh ctrl_user.sh create userfile
Changing password for user user1.
passwd: all authentication tokens updated successfully.
Changing password for user user2.
passwd: all authentication tokens updated successfully.
Changing password for user user3.
passwd: all authentication tokens updated successfully.
[root@localhost mnt]# sh ctrl_user.sh delete userfile
[root@localhost mnt]# id user1
id: user1: no such user

10.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
 
11.expect语句
在shell中利用expect实现自动应答脚本。
[root@localhost mnt]# vim ask.sh
#!/bin/bash
read -p "who are you: " USER
read -p "How old are you: " AGE
read -p "what's you study: " CLASS
read -p "How do you feel: " FEEL
echo $USER is $AGE\'s old study $CLASS and feel $FEEL
[root@localhost mnt]# chmod +x ask.sh
[root@localhost mnt]# sh ask.sh
who are you: mimi
How old are you: 12
what's you study: math
How do you feel: good
mimi is 12's old study math and feel good


12.
#!/usr/bin/expect
这一行告诉操作系统脚本里的代码使用那一个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开始,分别表示第一个,第二个,第三个....参数。


脚本实现
自动回答问题
[root@localhost mnt]# vim answer.exp
#!/usr/bin/expect
spawn /mnt/ask.sh
expect "Who"
send "mimi\r"
expect "old"
send "12\r"
expect "class"
send "math\r"
expect "feel"
send "good\r"
expect eof
[root@localhost mnt]# expect answer.exp
spawn /mnt/ask.sh
who are you: mimi
How old are you: 12
what's you study: math
How do you feel: good
mimi is 12's old study math and feel good


答案不为固定时,$argv 0,  $argv 1, $argv 2, $argv 3 表示脚本后面的第1,2,3,4个变量的值
[root@localhost mnt]# vim answer.exp
#!/usr/bin/expect
set NAME  [ lindex $argv 0 ]
set AGE   [ lindex $argv 1 ]
set CLASS [ lindex $argv 2 ]
set FEEL [ lindex $argv 3 ]
spawn /mnt/ask.sh
expect "Who"
send "$NAME\r"
expect "old"
send "$AGE\r"
expect "class"
send "$CLASS\r"
expect "feel"
send "$FEEL\r"
expect eof
[root@localhost mnt]# expect answer.exp  mimi 12 math good  ##脚本加变量执行后自动生成答案
spawn /mnt/ask.sh
who are you: mimi
How old are you: 12
what's you study: math
How do you feel: good
mimi is 12's old study math and feel good

实现功能
脚本+ip+password自动ssh远程链接
[root@localhost mnt]# vim authssh.exp
#!/usr/bin/expect
set IP [ lindex $argv 0 ]
set PASS [ lindex $argv 1 ]
spawn ssh root@$IP
expect {
        "yes/no" { send "yes\r";exp_continue }
        "password:" { send "$PASS\r" }
}
interact


脚本读主机密码记录文显示主机名
[root@localhost mnt]# vim hostname
172.25.254.6 westos
172.25.254.134 redhat


[root@localhost mnt]# vim check_hostname.sh
#!/bin/bash
if
[ -n "$*" ]
then
        LINE=`wc -l $* | awk '{print $1}'`
        for NUM in `seq 1 $LINE`
        do
        IP=`sed -n ${NUM}p $* | awk '{print $1}'`
        PASS=`sed -n ${NUM}p $* | awk '{print $2}'`
        /mnt/autossh.exp $IP $PASS hostname | tail -n 1
        done
else
        echo "Useage:check_host.sh <filename>"
fi

13.环境变量
shell中的变量分为三类:环境级,用户级,系统级
环境级:重新打开一个shell即时失效


用户级:只能在设置的用户使用,切换则失效
[root@localhost ~]# vim .bash_profile


系统级:整个系统都有效
[root@localhost ~]# vim /etc/profile


shell和脚本使用变量来存储数据 ,有些变量可以连同它们的内容传递给子进程,这些变量我们称之为环境变量。
[root@localhost mnt]# qq=redhat
[root@localhost mnt]# echo $qq
redhat
[root@localhost mnt]# bash
[root@localhost mnt]# echo $qq

[root@localhost mnt]# exit
exit
[root@localhost mnt]# export qq
[root@localhost mnt]# bash
[root@localhost mnt]# echo $qq
redhat
[root@localhost mnt]# exit
exit

14.使用env命令显示所有环境变量
使用set命令现实所有本地定义的shell变量Bash启动脚本在用户登录的时候,会运行全局变量文件/etc/profile,和用户自定义~/.bash_profile去初始化它们的环境变量。
/etc/profile
\_ /etc/profile.d/*.sh
~/.bash_profile
\_ ~/.bashrc
\_ /etc/bashrc


15.使用别名
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


[root@localhost ~]# vim /etc/bashrc
alias xie='vim'    ##给vim命令设置别名xie
[root@localhost ~]# xie file  ##不可执行命令
bash: xie: command not found...
[root@localhost ~]# source  /etc/bashrc ##刷新,使生效
[root@localhost ~]# xie file  ##xie为可执行命令
[root@localhost ~]# unalias xie  ##是使别名失效
[root@localhost ~]# xie fie
bash: xie: command not found...

16.使用函数
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


原创粉丝点击