单分支if语句:

if 条件; then

语句1

语句2

...

fi



if 条件

then


例子1:写一个脚本,实现如下功能:

如果用户存在,就说明其存在;


#!/bin/bash

#

UserName=user1


if grep "^$UserName\>" /etc/passwd &> /dev/null; then

echo "$UserName exists."

fi



#!/bin/bash


UserName=user1


if id $UserName &> /dev/null; then

echo "$UserName exists."

fi



练习:写一个脚本,实现如下功能:

如果用存在,就显示其UID和SHELL;

#!/bin/bash

#

UserName=user1

if id $UserName &> /dev/null; then

grep "^$UserName\>" /etc/passwd | cut -d: -f3,7

fi


练习:写一个脚本,实现如下功能:

如果设备/dev/sda3已经挂载,就显示其挂载点;

#!/bin/bash

#

Device='/dev/sda3'


if mount | grep "^$Device" &> /dev/null; then

mount | grep "/dev/sda3" | cut -d' ' -f3

fi



练习:写一个脚本,实现如下功能:

如果/etc/rc.d/rc.sysinit中有空白行,就显示其空白行数;

#!/bin/bash

#

File='/etc/rc.d/rc.sysinit'


if grep "^$" $File &> /dev/null; then

grep "^$" $File | wc -l

fi




双分支if语句:

if 条件; then

语句1

语句2

...

else

语句1

语句2

...

fi


例子:写一个脚本:

如果指定的用户存,先说明其已经存在,并显示其ID号和SHELL;否则,就添加用户,并显示其ID号;


练习:写一个脚本,实现如下功能:

如果设备/dev/sda3已经挂载,就显示其挂载点;否则,就说明其未挂载或设备不存在;


#!/bin/bash

#

Device='/dev/sda3'


if mount | grep "^$Device" &> /dev/null; then

mount | grep "/dev/sda3" | cut -d' ' -f3

else

echo "$Device not mounted or not exist."

fi



bash条件测试:

[ expression ]

` expression `

test expression


整数测试

字符测试

文件测试


整数测试:

expression: 数值1 比较符号 数值2

$A 比较符号 $B

大于:-gt, 例如 $A -gt $B

大于或等于:-ge

等于:-eq

小于:-lt

小于或等于:-le

不等于:-ne


例子:写一个脚本,生成两个随机数,比较其大小;显示大数;

bash有个内置变量:$RANDOM


#!/bin/bash

#

A=$RANDOM

B=$RANDOM


if [ $A -ge $B ]; then

echo "Max number is $A."

else

echo "Max number is $B."

fi


练习:写一脚本,随机生成一个整数,判定,显示其奇偶性;

#!/bin/bash

#

A=$RANDOM


if [ $[$A%2] -eq 0 ]; then

echo "$A: Even"

else

echo "$A: Odd"

fi


练习:给定一个用户,如果其ID号大于499,就说明其是普通用户,否则,就说明其是管理员或系统用户;

#!/bin/bash

#

UserName=daemon


Uid=`id -u $UserName`


if [ $Uid -gt 499 ]; then

echo "A common user: $UserName."

else

echo "admin user or system user: $UserName."

fi



练习:求200以内所有为3的整数倍的整数之和;

#!/bin/bash

#

Sum=0


for I in {1..200}; do

if [ $[$I%3] -eq 0 ]; then

Sum=$[$Sum+$I]

fi

done


echo "Sum: $Sum."



练习:给定一个用户,如果其UID等于GID,就说明这是个“good guy”,否则,“Bad guy.”

#!/bin/bash

#

UserName=user1


if [ `id -u $UserName` -eq `id -g $UserName` ]; then

echo "Good Guy."

else

echo "Bad Guy."

fi



写一个脚本:

计算100以内所有奇数的和以及所有偶数的和;分别显示之;


#!/bin/bash

#

EvenSum=0

OddSum=0


for I in {1..100}; do

if [ $[$I%2] -eq 0 ]; then

EvenSum=$[$EvenSum+$I]

else

OddSum=$[$OddSum+$I]

fi

done


echo "EvenSum is: $EvenSum. OddSum is: $OddSum."




bash编程: 位置变量

$1, $2, $3, $4, ...



写一个脚本:

计算N以内所有奇数的和以及所有偶数的和;分别显示之;N是通过参数传递过来的正整数;


#!/bin/bash

#

EvenSum=0

OddSum=0


for I in `seq 1 $1`;do

if [ $[$I%2] -eq 1 ]; then

OddSum=$[$OddSum+$I]

else

EvenSum=$[$EvenSum+$I]

fi

done


echo "EvenSum: $EvenSum."

echo "OddSUm: $OddSum."


echo "Sum: $[$EvenSum+$OddSum]"





shift [n]:实现位置参数轮替;



例子:通过参数传递n个正整数给脚本,求其和;

#!/bin/bash

#

Sum=0

for I in `seq 1 $#`; do

Sum=$[$Sum+$1]

shift

done


echo $Sum




练习,写一个脚本,完成以下要求:

1、添加10个用户user1, user2, ..., user10;但要先判断用户是否存在,不存在而后再添加;

2、添加完成后,显示一共添加了几个用户;当然,不能包括因为事先存在而没有添加的;

3、最后显示当前系统上共有多少个用户;

#!/bin/bash

#

Count=0


for I in {1..10}; do

if id user$I &> /dev/null; then

echo "user$I exists."

else

useradd user$I

echo "Add user$I successfully."

Count=$[$Count+1]

fi

done


echo "Add $Count new users."

echo "Total users: `wc -l /etc/passwd | cut -d' ' -f1`."



练习,写一个脚本,完成以下要求:

1、通过参数传递一系列用户名给脚本,让脚本添加这些用户;但要先判断用户是否存在,不存在而后再添加;

2、添加完成后,显示一共添加了几个用户;当然,不能包括因为事先存在而没有添加的;

#!/bin/bash

#

Count=0


for UserName in $@; do

if id $UserName &> /dev/null; then

echo "$UserName exists."

else

useradd $UserName

echo "Add $UserName successfully."

Count=$[$Count+1]

fi

done


echo "Add $Count new users."


练习,写一个脚本,完成以下要求:

给定一个用户:

1、如果其UID为0,就显示此为管理员;

2、否则,就显示其为普通用户;


练习:写一个脚本,完成以下要求:

通过参数传递一个磁盘设备文件给脚本,让脚本来判断其是否有扩展分区;有则显示有,否则显示为无;



练习:写一个脚本

给定一个文件,比如/etc/inittab

判断这个文件中是否有空白行;

如果有,则显示其空白行数;否则,显示没有空白行。




练习:写一个脚本;(要求:不使用id命令获得其id号;)

给定一个用户,判断其UID与GID是否一样

如果一样,就显示此用户为“good guy”;否则,就显示此用户为“bad guy”。



练习:写一个脚本

给脚本传递两个参数(整数);

显示此两者之和,之乘积;




写一个脚本,分别显示当前系统上所有默认shell为bash的用户和默认shell为/sbin/nologin的用户,并统计各类shell下的用户总数。显示结果形如:

BASH,3users,they are:

root,redhat,gentoo


NOLOGIN, 2users, they are:

bin,ftp




bash脚本知识点:

条件测试方式:

bash命令;

[ expression ]

` expression `

test expression


条件测试:

整数测试

大于:-gt

小于:-lt

等于:-eq

大等:-ge

小等:-le

不等:-ne

字符测试

文件测试


命令执行状态返回值: 0-255

0: 正确执行

1-255: 错误执行

exit [n]

脚本执行的最后一条件命令的状态返回值;


bash字符测试:

>: 大于

<: 小于

==: 等于

=~: 判断左边的字符串是否能够被右边的模式所匹配;通常用于[[]];

[[ $opt1 =~ $opt2 ]]

一般做行首、行尾锚定;不要加引号;


单目:

-z $STRING: 为空则为真,不空则为假;

-n $STRING: 为空则为假,不空则真;


例子:写一个脚本,判定用户的shell是否为bash;

[ "$Shell" == "/bin/bash" ]



#!/bin/bash

#


Shell=`grep "^$1:" /etc/passwd | cut -d: -f7`


if [ "$Shell" == "/bin/bash" ]; then

echo "Bash User."

Ret=0

else

echo "Not Bash User."

Ret=9

fi


exit $Ret


改进版:

#!/bin/bash

#


Shell=`grep "^$1:" /etc/passwd | cut -d: -f7`


if [ -z $Shell ]; then

echo "No such user or User's shell is null."

exit 10

fi


if [ "$Shell" == "/bin/bash" ]; then

echo "Bash User."

Ret=0

else

echo "Not Bash User."

Ret=9

fi


exit $Ret


例子:根据用户shell的结束符是否为sh来判定其是否为登录用户:

#!/bin/bash

#


Shell=`grep "^$1:" /etc/passwd | cut -d: -f7`


if [ -z $Shell ]; then

echo "No shell."

exit 3

fi


if [[ "$Shell" =~ sh$ ]]; then

echo "Login User."

Ret=0

else

echo "None Login User."

Ret=4

fi


exit $Ret



写一个脚本:

判断当前主机的CPU生产商,其信息在/proc/cpuinfo文件中vendor id一行中。

如果其生产商为GenuineIntel,就显示其为Intel公司;

否则,就显示其为AMD公司;


#!/bin/bash

#

Vendor=`grep "vendor_id" /proc/cpuinfo | uniq | cut -d: -f2`


if [[ "$Vendor" =~ [[:space:]]*GenuineIntel$ ]]; then

echo "Intel"

else

echo "AMD"

fi


练习:写一个脚本

通过参数传递一个字符串给脚本,如果传递的字符串为“memory”或“Memory”,就以MB为单位显示当前主机的内存信息;

否则,就显示/proc/uptime文件的内容。

#!/bin/bash

#

if [[ $1 =~ [Mm]emory$ ]]; then

free -m

else

cat /proc/uptime

fi



bash知识点:组合条件测试

-a: 与

-o: 或

!: 非,单目操作符


A=3

UID>=1, UID<=499


bash测试:

bash命令

[]

[[]]

test


bash命令组合测试:

&&: 与

||: 或

!: 非


写一脚本,给定用户,如果其不存在,就退出脚本。

if ! id $1 &> /dev/null; then

echo "No such user."

exit 6

fi


if [ `id -u $1` -eq `id -g $1` ]; then

echo "Good Guy"

else

echo "Bad Guy"

fi


练习:写一个脚本

通过参数传递一个字符串给脚本,如果传递的字符串为“memory”或“Memory”,就以MB为单位显示当前主机的内存信息;

否则,就显示/proc/uptime文件的内容。

[ $1 == "memory" -o $1 == "Memory" ]



bash条件判断之多分支if语句:

语法格式:

if 条件1; then

语句1

语句2

...

elif 条件2; then

语句1

语句2

...

elif 条件3; then

语句1

语句2

...

else

语句1

语句2

...

fi


写一个脚本:

判断当前主机的CPU生产商,其信息在/proc/cpuinfo文件中vendor id一行中。

如果其生产商为GenuineIntel,就显示其为Intel公司;

如果其生产商为AuthenticAMD,就显示其为AMD公司;

否则,就显示无法识别;

#!/bin/bash

#

Vendor=`grep "vendor_id" /proc/cpuinfo | uniq | cut -d: -f2`


if [[ $Vendor =~ [[:space:]]*GenuineIntel$ ]]; then

echo "intel"

elif [[ $Vendor =~ [[:space:]]*AuthenticAMD$ ]]; then

echo "AMD"

else

echo "Unknown"

fi


练习:通过参数传递给脚本一个字符串,如Fedora, Gentoo, Redhat,判断Linux发行版所处理主流发行系列:

如果为fedora, centos, redhat,就显示RedHat;

[ $1 == fedora -o $1 == centos -o $1 == redhat ]

如果为suse, opensuse,就显示为SUSE;

如果为ubuntu, mint, debian,就显示为Debian;

否则,显示为其它或无法识别;


写一个脚本,其可以接受三个参数,最后一个参数为文件名,但参数可变化,形如:

script.sh -a MageEdu /magedu.com/scripts/test1.sh

script.sh -d 2013-07-19 /magedu.com/scripts/test1.sh

script.sh -D 'some infomation' /magedu.com/scripts/test1.sh

此脚本能够创建/magedu.com/scripts/test1.sh文件,并且,如果给出了-a MageEdu,则文件前两行为:

#!/bin/bash

# Author: MageEdu

如果给出了-d 2013-07-19,则文件前两行为:

#!/bin/bash

# Date: 2013-07-19

如果给出了-D "some infomation",则文件前两行为:

#!/bin/bash

# Description: some infomation

其它任何参数,均提示错误并退出;


进一步:如果没有退出,则使用vim打开此文件,并使用光标默认处于最后一行;


再进一步:保存退出后,如果文件有语法错误提示用户有错误;


更进一步:如果没有语法错误,则给些文件赋予执行权限;


a.sh -a mageedu /tmp/test.sh

#!/bin/bash

# Author: mageedu


a.sh -d 2013-07-19 /tmp/test.sh

#!/bin/bash

# Date: 2013-07-19


a.sh -D "test script" /tmp/test.sh

#!/bin/bash

# Description: test script


mkscript





#!/bin/bash


if [ $# -ne 3 ]; then

echo "the number of arguements is wrong."

exit 4

fi


echo '#!/bin/bash' >> $3


if [ $1 == '-a' ]; then

echo "# Author: $2" >> $3

elif [ $1 == '-d' ]; then

echo "# Date: $2" >> $3

elif [ $1 == '-D' ]; then

echo "# Description: $2" >> $3

else

echo "Unknown option, ignore it."

rm -f $3

exit 5

fi


vim + $3


if bash -n $3 &> /dev/null; then

chmod +x $3

else

echo "Syntax wrong in $3."

fi




bash测试之文件测试:

操作符 文件路径

-f: 测试其是否为普通文件,即ls -l时文件类型为-的文件;

-d: 测试其是否为目录文件,即ls -l时文件类型为d的文件;

-e: 测试文件是否存在;存在为真,否则为假;

-r: 测试文件对当前用户来说是否可读;

-w: 测试文件对当前用户来说是否可写;

-x: 测试文件对当前用户来说是否可执行;

-s: 测试文件大小是否不空,不空则真,空则假;


如果/tmp/test10不存在,就创建之;

if [ ! -e /tmp/test10 ]; then

mkdir /tmp/test10

fi



短路操作:只要前半段已经可以决定最终结果,后半段就不再运算;

与运算:

真 && 真 = 真

真 && 假 = 假

假 && {真|假} = 假


或运算:

假 || 0 = 0

假 || 1 = 1


真 || =1




[ -e /tmp/test10 ] || mkdir /tmp/test10



id $UserName &> /dev/null || useradd $UserName


! id $UserName &> /dev/null && useradd $UserName || echo "$UserName exists."

id $UserName &> /dev/null && echo "$UserName exists." || useradd $UserName



例子:给定一个路径,判断

如果为普通文件,显示之;

如果为目录,显示之;

否则,说无法识别;


#!/bin/bash

#

if [ ! -e $1 ]; then

echo "No such file."

exit 7

fi


if [ -f $1 ]; then

echo "Common file."

elif [ -d $1 ]; then

echo "Directory."

else

echo "Unknown file."

fi


bash的特殊参数:$0: 脚本名称;


/tmp/script.sh


basename $0



写一个脚本:可以接受一个参数,其使用形式如下:

script.sh {start|stop|restart|status}

如果参数为start,创建空文件/var/lock/subsys/script,并显示“Starting script successfully.”;

如果参数为stop,则删除文件/var/lock/subsys/script,并显示“Stop script finished.”;

如果参数为restart,则删除文件/var/lock/subsys/script后重新创建,并显示“Restarting script successfully.”;

如果参数为status,那么:

如果/var/lock/subsys/script文件存在,则显示为“script is running.”

否则,则显示为“script is stopped.”

其它任何参数:则显示“script.sh {start|stop|restart|status}”


进一步:修改start的机制为:

如果参数为start,且/var/lock/subsys/script文件不存在,则创建空文件/var/lock/subsys/script,并显示“Starting script successfully.”;

否则,显示“script is already running.”


进一步:修改stop的机制为:

如果参数为stop,且/var/lock/subsys/script文件存在,则删除文件/var/lock/subsys/script,并显示“Stop script finished.”;

否则,显示“script is stopped yet.”



SysV网络服务脚本:

# service network restart


# /etc/rc.d/init.d/network start


# /etc/init.d/network start




#!/bin/bash

#

SvcName=`basename $0`

LockFile="/var/lock/subsys/$SvcName"


if [ $# -lt 1 ]; then

echo "Usage: $SvcName {start|stop|restart|status}"

exit 3

fi


if [ $1 == 'start' ]; then

if [ -e $LockFile ]; then

echo "$SvcName is running."

else

touch $LockFile &> /dev/null

echo "Starting $SvcName successfully."

fi

elif [ $1 == 'stop' ]; then

if [ -e $LockFile ];then

rm -f $LockFile &> /dev/null

echo "Stopping $SvcName finished."

else

echo "$SvcName is stopped yet."

fi

elif [ $1 == 'restart' ]; then

rm -f $LockFile &> /dev/null

touch $LockFile &> /dev/null

echo "Restarting $SvcName successfully."

elif [ $1 == 'status' ]; then

if [ -e $LockFile ]; then

echo "$SvcName is running."

else

echo "$SvcName is stopped."

fi

else

echo "Usage: $SvcName {start|stop|restart|status}"

exit 4

fi



字符串测试:

>

<

==

!=

-z

-n

=~:模式匹配检测;

文件测试:

-e

-f

-d

-r

-w

-x

-s


测试条件的逻辑组合:组合测试

与:-a

或:-o

非:!


与:&&

或:||

非:!


if [ $# -gt 1 -a $# -lt 10 ]


if id $UserName &> /dev/null && [ `id -u $UserName` -ge 500 ]; then




练习:写一个脚本

给定一个文件:

如果是一个普通文件,就显示之;

如果是一个目录,亦显示之;

否则,此为无法识别之文件;

File=

if [ -f $File ]; then

echo

elif [ -d $File ]; then

echo

else

echo

fi


判断某目录中所有文件的类型:

for File in /var/log/*; do

if [ -f $File ]; then

echo

elif [ -d $File ]; then

echo

else

echo

fi

done



bash的编程之case语句:用法格式


case 变量引用(${}) in

value1)

语句1

语句2

...

;;

value2)

语句1

语句2

...

;;

value3)

语句1

语句2

...

;;

*)

语句1

语句2

...

;;

esac


#!/bin/bash

#


Com=$1


if [ -z $Com ]; then

Com=gzip

fi


[ -d /backup ] || mkdir /backup


case $Com in

gzip)

tar zcf /backup/etc-`date +%F-%H-%M-%S`.tar.gz /etc/*

RetVal=$?

;;

bzip2)

tar jcf /backup/etc-`date +%F-%H-%M-%S`.tar.bz2 /etc/*

RetVal=$?

;;

xz)

tar Jcf /backup/etc-`date +%F-%H-%M-%S`.tar.xz /etc/*

RetVal=$?

;;

*)

echo "Usage: `basename $0` {[gzip|bzip2|xz]}"

exit 6

;;

esac


[ $RetVal -eq 0 ] && echo "Backup etc finished.($Com)."



case语句解决上一个服务脚本的问题:

#!/bin/bash

#

SvcName=`basename $0`

LockFile=/var/lock/subsys/$SvcName


if [ $# -lt 1 ]; then

echo "Usage: $SvcName {start|restart|stop|status}"

exit 5

fi


case $1 in

start)

touch $LockFile

echo "Starting $SvcName finished." ;;

stop)

rm -f $LockFile

echo "Stopping $SvcName finished." ;;

restart)

rm -f $LockFile

touch $LockFile

echo "Restarting $SvcName finished." ;;

status)

if [ -e $LockFile ]; then

echo "$SvcName is running..."

else

echo "$SvcName is stopped..."

fi

;;

*)

echo "Usage: $SvcName {start|restart|stop|status}"

exit 6

esac



练习:判断当前Linux发行版是RedHat, Fedora, CentOS还是其它。

方法:取得/etc/issue文件第一行的第一个单词后进行比较;



bash如何与用户交互:bash内置命令, read

-p "prompt":提示信息

-t #: 超时秒数


例子:

#!/bin/bash

#


read -p "Do you agree [yes|no]?: " YesNo


case $YesNo in

y|Y|[Yy]es)

echo "Agreed, proceed." ;;

n|N|[nN]o)

echo "Disagreed, can't proceed." ;;

*)

echo "Invalid input." ;;

esac



例子:写一个脚本

1、显示如下菜单给用户:

m|M) show memory usages;

d|D) show disk usages;

q|Q) quit

2、如果用户选择了第一项,则显示内存使用信息;

如果选择了第二项,则显示磁盘挂载及使用相关信息;

如果是第三项,退出,并显示选择退出;

其它任何内容,均说明错误选项;


#!/bin/bash

cat << EOF

m|M) show memory usages;

d|D) show disk usages;

q|Q) quit

EOF


read -p "Your choice: " Choice


case $Choice in

m|M)

free -m ;;

d|D)

df -lh ;;

q|Q)

echo "Quit..."

exit 0

;;

*)

echo "Invalid input."

exit 5

;;

esac