单分支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
|