首页 > 代码库 > bash 脚本

bash 脚本

bash 脚本

 

创建shell脚本

 

1 创建包含bash命令的文本文件

 

#!/bin/bash###写在文件的第一行,说明用什么解释器,来解释以下写的内容###

 

2 chmod  +x scripts

3  将文件放置在用户的$PATH的目录中

~/bin – 用于用户的私有程序

/usr/local/bin – 本地开发、系统上的其他人使用的脚本

/usr/local/sbin - 本地开发、由root使用的脚本

直接运行脚本和使用source命令运行脚本是不同的!

 

 

 

[root@server12 ~]# vim /mnt/test.sh

[root@server12 ~]# chmod +x /mnt/test.sh

[root@server12 ~]# /mnt/test.sh

^C

[root@server12 ~]# ps f###f看到从属关系###

  PID TTY      STAT   TIME COMMAND

 3819 pts/1    Ss     0:00 -bash

 3927 pts/1    R+     0:00  \_ ps f

 2656 pts/0    Ss+    0:00 /bin/bash

  611 tty1     Ss+    0:11 /usr/bin/Xorg :0 -background none -verbose -auth /run

 3218 ttyS0    Ss+    0:00 /sbin/agetty --keep-baud ttyS0 115200 38400 9600

 

脚本调试模式:

1 #!/bin/bash -x

2  bash -x scripts

 

+:指执行的命令,即输入

不带加号:输出结果

例:

[root@server12 ~]# bash -x /mnt/test3.sh

+ (( i=5 ))

+ (( i>=0 ))

+ echo 5

5

+ sleep 1

+ (( i-- ))

+ (( i>=0 ))

+ echo 4

4

+ sleep 1

+ (( i-- ))

+ (( i>=0 ))

+ echo 3

3

+ sleep 1

+ (( i-- ))

+ (( i>=0 ))

+ echo 2

2

+ sleep 1

+ (( i-- ))

+ (( i>=0 ))

+ echo 1

1

+ sleep 1

+ (( i-- ))

+ (( i>=0 ))

+ echo 0

0

+ sleep 1

+ (( i-- ))

+ (( i>=0 ))

 

引用和转义

 

引用和转义在shell解析字符串时用于去除字符串中特殊字符或保留词语的特殊含义。这会导致按字面处理字符串,而不是展开变量或将其部分内容视作具有特殊含义。

 

1 弱引用

双引号:弱引用, ` !  $ 不引用

将字符串放置在双引号中,保留字符串中所有字符的文字值, $、`、\和!字符除外,即` !  $ 不引用,仍会执行该特殊字符

例:显示"$5"

""$5""是错误的,前面的双引号是一对,后面的""是一对的,因此要用‘"$5"‘

 

2 强引用

单引号:转义所有字符

将字符串放置在单引号中,保留字符串中所有字符的文字值同时禁用所有扩展。

 

3 转义

非引用的\是转义字符。它保留了下一个字符的文字值。

\:转义

 

 

变量

shell变量用于为稍后在脚本中使用的名称指定值,并且仅限于shell命令行或从中声明变

量的脚本。

$变量:变量的值

 

 

命令替换

 

命令替换在子shell中执行指定命令并用命令输出替换脚本中的命令替换。

语法:

$(shell command)

 

:将/etc下的以.conf结尾的文件复制到/mnt下的etconf-年-月-日-秒的目录

 

#!/bin/bash

TODAY=$(date +%Y-%m-d-%S)

mkdir /mnt/etconfig.$(date +%Y-%m-%d-%S)

cp /etc/*.conf /mnt/etconfig.$(date +%Y-%m-%d-%S)

 

 

想要显示1b

a=1

echo ${a}b

 

 

 

循环

for循环用于值列表中的相同命令的重复

&&:前面的命令是正确的

||:错误的

 

1:将ip为172.25.254.1到172.25.254.10的主机开启的显示172.25.254.x 是up否则是down。

 

ping -c1 -w1 ###-c1 执行次数,-w1:等待时间

 

 

#!/bin/bash

for NUM in {1..10}

do

        ping -c1 -w1 172.25.254.$NUM &> /dev/null && echo 172.25.254.$NUM is up || echo 172.25.254.$NUM is down

done

 

 

2:建立一个用户文件,写一个脚本使得该用户可以被建立。

#!/bin/bash

COUNT=`wc -l username | cut -c 1`

for NUM in `seq 1 $COUNT`

do

 

        useradd `tail /root/username | sed -ne ${NUM}p`

done

 

3:5秒倒计时:

 

#!/bin/bash

for ((SEC=5;SEC>0;SEC--))

do

        echo -n After ${SEC}s is end###-n  ###不换行###

        echo -ne "\r\r"           ###-e 动作 ,\r 刷新,将前面的内容覆盖###

        sleep 1###每秒执行一次###

done

 

 

Shell计算命令

$[]表示数学运算

echo $[1+2]

(())表示数学运算。bash内建功能,效率高

 

例:循环与计算结合:

5秒倒计时:

 

#!/bin/bash

for ((SEC=5;SEC>0;SEC--))

do

        echo -n After ${SEC}s is end###-n  ###不换行###

        echo -ne "\r\r"           ###-e 动作 ,\r 刷新,将前面的内容覆盖###

        sleep 1###每秒执行一次###

done

 

 

bash位置参数

有两种简单的方法可以将用户输入读入bash中的变量。第一个方法是使用read提示用户输入(使用-p选项)并将其直接存储到一个或多个变量:

交互式输入

read -p

1:显示提示符:please give me a interface:输入接口eth0后,显示ip

 

#!/bin/bash

read -p "please give me a interface:"

ifconfig eth0 | grep netmask | awk -F " " ‘{print $2}‘

 

 

2:编写脚本,若是脚本后面没有字符,则显示please give me a ip address,当给出ip后判断能否ping的通,ping的通则显示ip is up,反之,则显示ip is down

#!/bin/bash

while [ "$#" -eq "0" ]### $#表示字符串的个数###

        do

        echo "please give me a ip address "

        exit 1

        done

ping -w1 -c1 $1 > /dev/null && echo "$1 is up" ||echo "$1 is down"

 

 

 

退出状态

 

Linux命令完成时,将返回退出状态。成功完成程序时,将返回0的推出状态。这被bash当作逻辑True值。非零退出状态通常表示发生了错误,并且被bash当作逻辑False值。

出状态的值被存储在"?"中,可以使用以下命令查看:

 echo $?

 

若为0,则表示命令是正确的

 

例:判断文件是否存在

#!/bin/bash

ls $1 &> /dev/null

[ "$?" -eq "0" ] && echo $1 is exist || echo $1 is not exist

 

 

test条件判断

test命令可用于评估bash脚本中的表达式。它评估其参数所指定的表达式,如果表达式为true,返回零退出状态,如果表达式为false,则返回非零退出状态。test具有替代语法,使用方括号"[]"将表达式括起来,这样更易于阅读

test n:非零  z:为零

 

例:

[root@desktop38 ~]# a=1

[root@desktop38 ~]# test -n "$a" ;echo $?

0

[root@desktop38 ~]# test -z "$a" ;echo $?

1

[root@desktop38 ~]# [ -n "$a" ] && echo yes

yes

[root@desktop38 ~]# [ -z "$a" ] && echo yes || echo no

no

 

1:写一个脚本/mnt/check_ip.sh,要求若脚本后面没有跟ip,则显示please give me a ipaddr,若是ping的通,就显示ip is up,否则显示ip is down

 

 

#!/bin/bash

[ -n "$*" ] &&(

        ping -c1 -w1 $* &> /dev/null && echo $* is up || echo $* is down

)||(

        echo "please give me a ipaddr"

)

 

字符串比较运算符:=、!=

数字比较运算符:-eq、-ne、-lt、-le、-gt、-ge

-eq :等于

-gt :大于

-ge:大于等于

-a:并且

-lt:小于

-le:小于等于

-o:或者

 

2:判断两个数字和的大小

 

#!/bin/bash

while [ "$#" -lt 2 ]

do

echo "please give two number"

exit 1

done

COUNT=$[ $1+$2 ]

while [ $COUNT -lt 10 ]

do

echo "the sum is smaller than 10"

break

done

while [ $COUNT -ge 10 ]

do

echo "the sum is bigger than 10"

break

done

 

不用while,则:

(NUM=$1+$2))

[ "$NUM" -lt "10" ]&& echo "the sum is smaller than 10" || echo "the sum is bigger than 10"

 

 

文件状态运算符:test -{b|c|e|f|d|r|w|x|s|L}

-b:表示文件类型为块设备

-c:字符设备

-d:目录

-L:链接

-S:套接字

-:文件

-f:常规文件

-e:表示存在

二进制文件运算符:-ef、-nt、-ot

-ef:硬连接

-nt:哪个文件新

-ot:哪个文件老

 

例:判断文件类型

#!/bin/bash

if

[ "$#" -eq "0" ]

then

        echo "please give mw a file"

elif

[ ! -e $1 ]

then

        echo "$1 is not exist"

elif

[ -L "$1" ]

then

        echo "$1 is a soft link"

elif

[ -d "$1" ]

then

        echo "$1 is a directory"

fi

 

 

if语句

 

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

 

1:建立用户

 

#!/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`

        [ -z $USER ]&&(

        useradd $NAME

        echo westos | passwd --stdin $NAME &>/dev/null

        )||(

        echo "$NAME is exist"

        )

        done

fi

 

或者:

 

#!/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`

        if

[ -z "$USER" ]

then

useradd $NAME

echo westos | passwd --stdin $NAME  &> /dev/null

else

echo $NAME is exit!!

fi

done

fi

 

2:当脚本后面接create时,建立/mnt/userfile的用户,当脚本后面接delete,删除/mnt/userfile的用户。

 

#!/bin/bash

if

[ "$#" -lt "2" ]

then

echo "Usage: /mnt/ctrl_user.sh <create|delete> <userfile>"

fi

if

[ "$1" = "create" ]

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`

        [ -z $USER ]&&(

        useradd $NAME &> /dev/null

        echo westos | passwd --stdin $NAME &>/dev/null

        )||(

        echo "$NAME is exist"

        )

        done

fi

elif

[ "$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`

        [ -n $USER ]&&(

        userdel -r $NAME &> /dev/null

        )||(

        echo "$NAME is not  exist"

        )

        done

fi

fi

 

 

十一 case语句

 

case语句 :它能够把变量的内容与多个模板进行匹配,再根据成功匹配的模板去决定应该执行哪

部分代码。

 

2:当脚本后面接create时,建立/mnt/userfile的用户,当脚本后面接delete,删除/mnt/userfile的用户。

 

#!/bin/bash

case "$1" in

        create)

        [ "$#" -lt "2" ] && echo "Usage: /mnt/ctrl_user.sh <create|delete> <userfile>" || ( for NAME in `cat $2`

                do

                USER=`getent passwd $NAME`

                [ -z $USER ] && (

                useradd $NAME &> /dev/null

                echo westos | passwd --stdin $NAME &> /dev/null

                ) || (echo "$NAME is exit")

                done

        )

        ;;

        delete)

        [ "$#" -lt "2" ] && echo "Usage: /mnt/ctrl_user.sh <create|delete> <userfile>" || ( for NAME in `cat $2`

                do

                USER=`getent passwd $NAME`

                [ -n $USER ] && (

                userdel -r  $NAME &> /dev/null

                ) || (echo "$NAME is  not exit")

                done

        )

        ;;

esac

 

十一 expect 语句

 

shell中利用expect实现自动应答脚本

 

#!/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开始,分别表示第

一个,第二个,第三个....参数。

 

1:expect的使用示例

 

yum install expect -y

[root@localhost ~]# which expect

/usr/bin/expect

[root@desktop38 ~]# vim /mnt/ask.sh

#!/bin/bash

read -p "Who are you: " NAME

read -p "How old  are you: " AGE

read -p "what‘s you class: " CLASS

read -p "Are you happy: " FEEL

echo $NAME is $AGE old study $CLASS and feel $FEEL

 

[root@desktop38 ~]# 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###监控/mnt/ask.sh

expect "Who"###\r换行###

send "$NAME\r"

expect "How"

send "$AGE\r"

expect "class"

send "$CLASS\r"

expect "happy"

send "$FEEL\r"

expect eof###退出expect###

 

 

测试:

[root@desktop38 ~]# expect answer.exp

spawn /mnt/ask.sh

Who are you:

How old  are you:

what‘s you class:

Are you happy:

is old study and feel

[root@desktop38 ~]# expect answer.exp hello 18 linux happy

spawn /mnt/ask.sh

Who are you: hello

How old  are you: 18

what‘s you class: linux

Are you happy: happy

hello is 18 old study linux and feel happy

 

2:用expect编写登入172.25.254.178

 

#!/usr/bin/expect

set ip [ lindex $argv 0]

spawn ssh root@$ip

set password [ lindex $argv 1 ]

expect {###一个expect回答两个问题###

        "yes/no" {send "yes\r";exp_continue}###exp_continue表示如果有这个问题,就回答,没有往下继续###

        "password:" {send "$password\r"}

}

interact###表示停留在expect界面###

 

 

测试:

[root@localhost ~]# vim /mnt/test2.exp

Connection to 172.25.254.178 closed.

[root@localhost ~]# expect /mnt/test2.exp 172.25.254.178 redhat

spawn ssh root@172.25.254.178

root@172.25.254.178‘s password:

Last login: Tue Jun 20 23:40:20 2017 from 172.25.254.17

 

 

 

 

十二 环境变量

shell和脚本使用变量来存储数据 ,有些变量可以连同它们的内容传递给子进程,这些

变量我们称之为环境变量

使用env命令显示所有环境变量

使用set命令现实所有本地定义的shell变量

环境级变量:只针对当前环境生效

用户级变量:只针对用户生效~/.bash_profile

系统级变量:所有用户都生效/etc/profile

 

在用户登录的时候,会运行全局变量文件/etc/profile,和用户自定义变量文件~/.bash_profile去初始化它们的环境变量。

例:####使用export a=1,能够使bash下的子bash也识别该变量,但是,当该bash关闭后,再次登入后就识别不了

[root@desktop38 ~]# a=1

[root@desktop38 ~]# echo $a

1

[root@desktop38 ~]# vim file

内容:

 

echo $a

 

[root@desktop38 ~]# sh file

 

[root@desktop38 ~]# export a=1###使得该变量在该环境下均可以用###

[root@desktop38 ~]# sh file

1

[root@desktop38 ~]#

 

 

若是想要该用户在该bash关闭再次打开后仍能够识别该变量,则需要在~/.bash_profile下编写export  变量=变量的值,但当你切换用户的时候仍然不能使用该变量,此时就要在/etc/profile下编写

 

[root@localhost ~]# source .bash_profile ###使文件生效###

[root@localhost ~]# echo $a

1

[root@localhost ~]# tail -n 1 .bash_profile

export a=1

[root@localhost ~]# su - student

 

[student@localhost ~]$ echo $a

 

[student@localhost ~]$ exit

logout

[root@localhost ~]# vim /etc/profile

[root@localhost ~]# tail -n 1 /etc/profile

export a=2

[root@localhost ~]# source /etc/profile###在用户级文件和系统级文件均编写的情况下,哪个文件后生效,就使用哪个,一般是用户级的后生效,系统级的先生效###

[root@localhost ~]# echo $a

2

[root@localhost ~]# su - student

Last login: Mon Jun 19 23:59:37 EDT 2017 on pts/1

[student@localhost ~]$ echo $a

2

[student@localhost ~]$ exit

logout

[root@localhost ~]# source .bash_profile

[root@localhost ~]# echo $a

1

[root@localhost ~]# su - student

Last login: Tue Jun 20 00:05:27 EDT 2017 on pts/1

[student@localhost ~]$ echo $a

2

 

 

当要执行脚本时,就要写出该脚本的绝对路径,若不想写出绝对路径,可以在~/.bash_profile

/etc/profile下编写该文件的路径,例:export PATH=$PATH:/mnt

 

[root@localhost ~]# vim .bash_profile

[root@localhost ~]# tail -n  1 .bash_profile

export PATH=$PATH:/mnt

[root@localhost ~]# cd /mnt/

[root@localhost mnt]# ls

ctrl.user.sh  file  file.sh  password  test1.sh  test.sh  userfile

[root@localhost mnt]# cd

[root@localhost ~]# file.sh

1

[root@localhost ~]# su - student

Last login: Tue Jun 20 22:38:26 EDT 2017 on pts/1

[student@localhost ~]$ file.sh###要想所有用户均生效,在/etc/profile下编写###

bash: file.sh: command not found...

[student@localhost ~]$ exit

logout

[root@localhost ~]# vim /etc/profile

[root@localhost ~]# source  /etc/profile

[root@localhost ~]# su - student

Last login: Tue Jun 20 23:03:57 EDT 2017 on pts/1

[student@localhost ~]$ file.sh

2

[student@localhost ~]$

 

 

使用别名

alias命令可以用来自定义属于自己的系统命令,写入~/.bashrc 文件永久生效。

查看别名:

 

[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‘

 

设置别名:

alias mycom=‘echo hello;hostname‘

 

例:设置cat的别名kan

[root@localhost ~]# alias kan=‘cat‘

[root@localhost ~]# kan /mnt/file.sh

#!/bin/bash

echo $a

 

例:在文件例编写

[root@localhost ~]# vim /etc/profile

[root@localhost ~]# tail -n 1 /etc/pro

tail: cannot open ‘/etc/pro’ for reading: No such file or directory

[root@localhost ~]# tail -n 1 /etc/profile

alias xie=‘vim‘

[root@localhost ~]# source /etc/profile

[root@localhost ~]# alias

alias cp=‘cp -i‘

alias egrep=‘egrep --color=auto‘

alias fgrep=‘fgrep --color=auto‘

alias grep=‘grep --color=auto‘

alias kan=‘cat‘

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‘

alias xie=‘vim‘

[root@localhost ~]#

 

删除别名:

 

unalias mycomm

 

例:删除别名vim的别名xie

[root@localhost ~]# unalias xie

[root@localhost ~]# alias

alias cp=‘cp -i‘

alias egrep=‘egrep --color=auto‘

alias fgrep=‘fgrep --color=auto‘

alias grep=‘grep --color=auto‘

alias kan=‘cat‘

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 ~]# xie file

bash: xie: command not found...


bash 脚本