条件测试:
界定程序执行环境;(本质是判定程序是否执行)(1) 根据运行的命令的状态结果判定;
例如 id root &>/dev/null 等 (2) 测试表达式 test EXPRESSION [ EXPRESSION ] ` EXPRESSION `(建议多多使用此[[]],测试表达式和[]必须有空格)整数测试:隐含着做数值大小比较,所以不要给变量引用加引用;
$A -gt $B:是否大于;是则为“真”,否则为“假”; $A -ge $B: 是否大于等于; $A -lt $B:是否小于; $A -le $B: 是否小于等于; $A -eq $B: 是否等于; $A -ne $B:是否不等于;字符串测试:ASCII数值越大,字符比较时其值越大;
"$A" > "$B":是否大于; "$A" < "$B":是否小于; "$A" == "$B":是否等于; "$A" != "$B":是否不等于; -z "$A":是否为空;空则为“真”,否则为“假” -n "$A":是否不空;不空则“真”,空则为“假”如果首字符相同则比较第二个字符以此类推
注意:应该使用` EXPRESSION `文件测试:测试文件的存在性以及属性;
-e $file: 是否存在;存在则为“真”,否则为“假”; -a $file: 同上; -f $file:文件是否存在且为普通文件; -d $file:文件是否存在且为目录; -h $file:是否存在且为符号链接文件; -L $file: 同上 -b $file:是否存在且为块设备文件; -c $file:是否存在且为字符设备文件; -S $file:是否存在且为套接字文件; -p $file: 是否存在且为管道文件;-r $file: 当前用户对文件是否拥有读权限;
-w $file:当前用户对文件是否拥有写权限; -x $file:当前用户对文件是否拥有执行权限;-u $file:文件是否拥有SUID权限;
-g $file:文件是否拥有SGID权限; -k $file:文件是否拥有sticky权限;-O $file: 当前用户是否为指定文件的属主;
-G $file: 当前用户是否为指定文件的属组;双目操作符:
$file1 -nt $file2: file1是否新于file2, file1的最近一次的修改时间戳是否晚于file2 的; $file1 -ot $file2: file1是否旧于file2, file1的最近一次的修改时间戳是否早于file2 的; $file1 -ef $file2:file1与file2是否指向了同一个inode;测试二者是否为同一个文件 的硬链接;bash之条件判断(选择执行):
if/then, caseif CONDITION; then
if-true-分支(condition判定为真执行该段) fiif CONDITION; then
if-true-分支 else if-false-分支(condition判定为假执行该段) fi! CONDITION: 取反
练习:写一个脚本 如果某路径不存在,则将其创建为目录;否则显示其存在,并显示内容类型;#!/bin/bash # filename="/tmp/x/y/z/testdir" if [ -e $filename ]; then ##判定变量filename的变量值是否存在 echo "$filename exists." file $filename ##存在则执行以上两行操作 else ##不存在执行如下操作 mkdir -p $filename fi练习:写一个脚本,完成如下功能;
判断给定的两个数值,孰大孰小; 给定数值的方法:脚本参数,命令交互;#!/bin/bash # read -p "Plz enter two integer: " -t 10 num1 num2 ##与用户以交互方式 赋值变量num1 变量num2if [ -z "$num1" ]; then echo "Plz give two integers." exit 1 ##判定第一个参数是否为空 是则提示并退出脚本 fiif [ -z "$num2" ]; then echo "Plz give tow integers." exit 1 ##判定第一个参数是否为空 是则提示并退出脚本 fiif [ $num1 -ge $num2 ]; then ##判定变量num1的变量值是否大于变量num2的变量值 echo "Max: $num1, Min: $num2." ##变量num1大则执行此命令 else echo "Max: $num2, Min: $num1." ##变量num1小则执行此命令 fi多分支的if语句:
单分支: if CONDITION; then if-true-分支 fi双分支:
if CONDITION; then if-true-分支 () else if-false-分支 fi多分支:用于需要对多种情况判定是否执行时使用
if CONDITION1; then if-CONDITION1-true-分支 elif CONDTION2; then if-CONDITIO2-true-分支 ... else if-ALL-false-分支 fi示例:通过脚本参数传递一个文件路径给脚本,判断其类型;(文件只会符合一个判定条件)
#!/bin/bash # if [ $# -lt 1 ]; then echo "Usage: $0" exit 1 fi ##以上检测至少要有一个参数传递给脚本 否则脚本结束if [ -f $1 ]; then echo "Rgular file." ##传递的第一个参数是存在而且是普通文件 elif [ -d $1 ]; then echo "Directory." ##传递的第一个参数是存在而且是目录文件 elif [ -h $1 ]; then echo "Symbolic link." ##传递的第一个参数是存在而且是符号链接文件 elif [ -b $1 ]; then echo "Block special." ##传递的第一个参数是存在而且是块文件 elif [ -c $1 ]; then echo "Charactoer special." ##传递的第一个参数是存在而且是字符文件 elif [ -S $1 ]; then echo "Socket file." ##传递的第一个参数是存在而且是套接字文件 else echo "file not exist or unknown type." ##以上判定都不是则执行此命令 fi
示例:脚本可接受四个参数
start: 创建文件/var/lock/subsys/SCRIPT_NAME stop: 删除此文件 restart: 删除此文件并重新创建 status: 如果文件存在,显示为"running",否则,显示为"stopped"basename命令:
取得路径的基名;#!/bin/bash # prog=$(basename $0) ##取得脚本路径的基名赋值给变量prog lockfile="/var/lock/subsys/$prog" ##生产新的路径赋值给变量lockfile #echo $lockfileif [ $# -lt 1 ]; then echo "Usage: $prog start|stop|restart|status" exit 1 fi ##判定必须有至少一个参数传递给脚本if [ "$1" == "start" ]; then if [ -f $lockfile ]; then echo "$prog is started yet." ##判定传递来的参数是start 且$lockfile是普通文件则显示脚本is started yet else touch $lockfile && echo "Starting $prog ok..." || echo "Starting $prog failed..." ##判定传递来的参数是start 且$lockfile不存在,则创建$lockfile文件创建成功后显示Starting $prog ok.,如果创建失败则显示启动失败 fi elif [ "$1" == 'stop' ]; then if [ -f $lockfile ]; then rm -f $lockfile && echo "Stop $prog ok...." || echo "Stop $prog failed..." ##判定传递来的参数是stop且$lockfile是普通文件则强制删除$lockfile删除成功后显示Stop $prog ok....",如果删除失败则显示停止失败 else echo "$prog is stopped yet."##判定传递来的参数是stop且$lockfile不存在则显示$prog(取变量值 )is stopped yet fi elif [ "$1" == 'restart' ]; then if [ -f $lockfile ]; then rm -f $lockfile && touch $lockfile && echo "Restarting $porg ok..." ##判定传递来的参数是restart且$lockfile是普通文件则强制删除$lockfile删除成功后创建新的$lockfile,创建成功后显示Restarting $porg ok else touch $lockfile && echo "$prog is stopped, Starting $prog ok...." ##判定传递来的参数是restart且$lockfile不存在则创建新的$lockfile,创建成功后显示$prog is stopped, Starting $prog ok fi elif [ "$1" == 'status' ]; then if [ -f $lockfile ]; then echo "Running..." ##判定传递来的参数是status且$lockfile是普通文件则显示正在运行 else echo "Stopped..." ##判定传递来的参数是status且$lockfile不存在则显示已经停止 fi else echo "Usage: $prog start|stop|restart|sttus" exit 1 ##判定如传递来的参数不是start|stop|restart|sttus,则提示Usage: $prog start|stop|restart|sttus,然后错误结束脚本 ficase语句
简洁版多分支if语句; 使用场景:判断某变量的值是否为多种情形中的一种时使用;语法:
case $VARIABLE in PATTERN1) 分支1 ;; ##判定$VARIABLE符合PATTERN1则执行分支1命令PATTERN2)
分支2 ;; ##判定$VARIABLE符合PATTERN2则执行分支2命令 PATTERN3) 分支3 ;; ##判定$VARIABLE符合PATTERN3则执行分支3命令 ... *) 分支n ;; ##判定$VARIABLE符合PATTERNn则执行分支n命令 esacPATTERN可使用glob模式的通配符:
*: 任意长度的任意字符; ?: 任意单个字符; []: 指定范围内的任意单个字符; a|b: 多选1;示例:提示键入任意一个字符;判断其类型;
#!/bin/bash # read -p "Plz enter a character: " char ##提示输入一个字符 用交互方式复制给变量charcase $char in [a-z]) ##输入的为一个字母则显示为字母 echo "A character." ;; [0-9]) echo "A digit." ##输入的为一个数字则显示为数字 ;; *) echo "A special character." ##如果以上匹配不到,且输入的是任意长度的任意字符则显示为特殊字符 ;; esac
示例:脚本可接受四个参数
start: 创建文件/var/lock/subsys/SCRIPT_NAME stop: 删除此文件 restart: 删除此文件并重新创建 status: 如果文件存在,显示为"running",否则,显示为"stopped"#!/bin/bash # prog=$(basename $0) lockfile="/var/lock/subsys/$prog" #echo $lockfileif [ $# -lt 1 ]; then echo "Usage: $prog start|stop|restart|status" exit 1 ficase $1 in start) if [ -f $lockfile ]; then echo "$prog is started yet."##判定传递来的参数是start 且$lockfile是普通文件则显示脚本is started yet else touch $lockfile && echo "Starting $prog ok..." || echo "Starting $prog failed..." ##判定传递来的参数是start 且$lockfile不存在,则创建$lockfile文件创建成功后显示Starting $prog ok.,如果创建失败则显示启动失败 fi ;; stop) if [ -f $lockfile ]; then rm -f $lockfile && echo "Stop $prog ok...." || echo "Stop $prog failed..." ##判定传递来的参数是stop且$lockfile是普通文件则强制删除$lockfile删除成功后显示Stop $prog ok....",如果删除失败则显示停止失败 else echo "$prog is stopped yet." ##判定传递来的参数是stop且$lockfile不存在则显示$prog(取变量值 )is stopped yet fi ;; restart) if [ -f $lockfile ]; then rm -f $lockfile && touch $lockfile && echo "Restarting $porg ok..." ##判定传递来的参数是restart且$lockfile是普通文件则强制删除$lockfile删除成功后创建新的$lockfile,创建成功后显示Restarting $porg ok else touch $lockfile && echo "$prog is stopped, Starting $prog ok...." ##判定传递来的参数是restart且$lockfile不存在则创建新的$lockfile,创建成功后显示$prog is stopped, Starting $prog ok fi ;; status) if [ -f $lockfile ]; then echo "Running..." ##判定传递来的参数是status且$lockfile是普通文件则显示正在运行 else echo "Stopped..." ##判定传递来的参数是status且$lockfile不存在则显示已经停止 fi ;; *) echo "Usage: $prog start|stop|restart|sttus" exit 1 ##判定如传递来的参数不是start|stop|restart|sttus,则提示Usage: $prog start|stop|restart|sttus,然后错误结束脚本 esac
循环语句:
for, while, until循环:将循环体代码执行0、1或多次;
进入条件:进入循环的条件; 退出条件:循环终止的条件; 格式: for VARIABLE in LIST; do 循环体 doneLIST:是由一个或多个空格或换行符分隔开的字符串组成;
把列表的每个字符串逐个赋值给VARIABLE表示的变量;for username in user1 user2 user3; do
循环体 done进入条件:列表非空;
退出条件:列表遍历结束;添加10个用户,user1-user10;
#!/bin/bash # for username in user1 user2 user3 user4 user5; do ##循环进入标记列表仍有可以赋值,结束条件为列表参数全部赋值过 if id $username &> /dev/null; then echo "$username exists." else useradd $username echo "Add user $username finished." fi done
LIST的生成方法:
(1) 整数列表 (a) {start..end} (b) $(seq [start `step` end) (2) 直接给出列表 例如for username in user1 user2 user3 user4 user5 (3) glob (bash通配)例如 for file in /etc/f* (4) 命令生成 for file in $(ls /mnt)示例:数值列表
#!/bin/bash # for i in {1..10}; do ##直接给出列表 if id user$i &> /dev/null; then echo "user$i exists." else useradd user$i echo "Add user user$i finished." fi done
示例:glob
#!/bin/bash # for filename in /var/log/*; do ##轮值为/var/log下的所有文件 file $filename done
示例:命令生成列表
#!/bin/bash # for username in $(cut -d: -f1 /etc/passwd); do ##命令引用取列表为系统中的所有用户 echo "$username primary group: $(id -n -g $username)." done
示例:求100以内所以正整数之和;
#!/bin/bash # declare -i sum=0 for i in {1..100}; do 变量i的变量值轮1到100 sum=$[$sum+$i] ##将变量sum的变量值加上变量i的变量值所得值再重新赋值变量sum done echo $sum
示例:显示/etc目录下所有普通文件列表,而后统计一共有多少个文件;
#!/bin/bash # declare -i count=0 ##定义计数器 整型变量count for file in /etc/*; do ##使用通配方法生产/etc文件目录下的文件列表 if [ -f $file ]; then let count++ ##当是普通文件时计数器变量count自己+1 echo "$count $file" fi done echo "Total: $count files."
示例:写一个脚本实现如下功能;
获取当前主机的主机名; 如果当前主机的主机名为空,或者为localhost,则将其修改为www.magedu.com#!/bin/bash # hostname=$(hostname) ##命令引用取得命令执行结果赋值给变量hostnameif [ -z "$hostname" -o "$hostname" == "localhost" ]; then ##或表达式组合运用 hostname www.magedu.com fi
练习:写一个脚本,打印九九乘法表;
循环嵌套
1X1=1
1X2=2 2X2=4 1X3=3 2X3=6 3X3=9#!/bin/bash # for j in {1..9}; do for i in $(seq 1 $j); do ##双循环嵌套使用 保证被乘数不得大于乘数 echo -n -e "${i}X${j}=$[$i*$j]\t" done echo done
循环语句:for, while, until
while循环:
while CONDTION; do
循环体 done进入条件:当CONDITION为“真”;
退出条件:当CONDITION为“假”;while CONDITION; do
循环体 控制变量的修正表达式 (如果没有修正变量可能会死循环) done示例:求100以内所有正整数之和;
#!/bin/bash # declare -i sum=0 declare -i i=1 while [ $i -le 100 ]; do let sum+=$i let i++ done echo "Sum: $sum."
练习:分别求100以内所有奇数之和,及所有偶数之和;
#!/bin/bash#declare -i sum1=0declare -i sum2=0declare -i i=0while [ $i -le 100 ]; do if [ $[${i}%2] -eq 0 ]; then let sum1+=$i else let sum2+=$i fi let i++doneecho "qishu sum $sum2"echo "oushu sum $sum1"
示例:打印九九乘法表
#!/bin/bash # declare -i i=1 declare -i j=1while [ $j -le 9 ]; do while [ $i -le $j ]; do echo -e -n "${i}X${j}=$[$i*$j]\t" let i++ done echo let i=1 let j++ done
unitl循环:
until CONDITION; do 循环体 循环控制变量的修正表达式 done进入条件:当CONDITION为“假”时
退出条件:当CONDITION为“真”时示例:求100以内所有正整数之和
#!/bin/bash # declare -i sum=0 declare -i i=1 until [ $i -gt 100 ]; do let sum+=$i let i++ done echo "Sum: $sum."
练习1:分别求100以内所有偶数之和,以及所有奇数之和;
#!/bin/bash#declare -i sum1=0declare -i sum2=0declare -i i=0until [ $i -gt 100 ]; do if [ $[${i}%2] -eq 0 ]; then let sum1+=$i else let sum2+=$i fi let i++doneecho "qishu sum $sum2"echo "oushu sum $sum1"
练习2:实现九九乘法表;
#!/bin/bash##!/bin/bash#declare -i i=1declare -i j=1until [ $i -gt 9 ]; do until [ $j -gt $i ]; do echo -n "${j}x${i}=$[$j*$i] " let j++ done let j=1 let i++ echodone
练习3:分别使用while和until循环实现添加10个用户:user1-user10;
#!/bin/bash#declare -i i=1while [ $i -le 10 ]; do useradd user${i} let i++done
#!/bin/bash#declare -i i=1until [ $i -gt 10 ];do useradd user${i} let i++done
循环控制:
continue [n]:提前结束本轮循环,而直接进入下一轮; break [n]:提前结束循环;while循环:
while CONDITION; do ....... if CONDITION2; then break [n] fi donewhile CONDITION; do
...... if CONDITION2; then continue [n] fi ...... done示例:求100以内所有偶数之和;
#!/bin/bash # declare -i sum=0 declare -i i=0 while [ $i -le 100 ]; do let i++ if [ $[$i%2] -eq 1 ]; then echo "$i is a odd." continue fi let sum+=$i done echo "Sum: $sum."
死循环:
while true; do 循环体 if CONDTION; then break fi doneuntil false; do
循环体 if CONDITION; then break fi done示例:每隔3秒钟查看当前系统上是否有名为“gentoo”的用户登录;
如果某次查看gentoo登录了,则显示gentoo已经登录; 如果未登录,就显示仍然未来,并显示这是已经是第多少次查看了;
#!/bin/bash # username=$1 declare -i count=0 while true; do if who | grep "^$username" &> /dev/null; then echo "$username is logged." break else let count++ echo "$count $username is not login." fi sleep 3 done
#!/bin/bash # declare -i count=0 username=$1if [ $# -lt 1 ]; then echo "At lease one argument." exit 1 fiif ! id $username &> /dev/null; then echo "No such user." exit 2 fiuntil who | grep "^$username" &> /dev/null; do let count++ echo "$count $username is not login." sleep 3 doneecho "$username is logged on."
while循环的特殊用法:
遍历文件的每一行: while read VARIABLE; do 循环体 done < /PATH/FROM/SOME_FILE示例:找出UID为偶数的所有用户,显示其用户名和ID号;
#!/bin/bash # while read line; do userid=$(echo $line | cut -d: -f3) if [ $[$userid%2] -eq 0 ]; then echo $line | cut -d: -f1,3 fi done < /etc/passwd
for循环的特殊用法:
for ((expr1;expr2;expr3)); do 循环体 doneexpr1: 定义控制变量,并初始赋值;
expr2: 循环控制条件; 进入条件:控制条件为“真” 退出条件:控制条件为“假” expr3: 修正控制变量示例:求100以内所有正整数之和;
#!/bin/bash # declare -i sum=0 for ((i=1;i<=100;i++)); do let sum+=$i done echo "Sum: $sum."
练习1:打印九九乘法表;
#!/bin/bash#for (( i=1;i<10;i++));do for (( j=1;j<=i;j++));do echo -n "${j}x$i=$[ $j*$i ] " done echodone
练习2:传递一个文本文件为参数给脚本,取出此文件的所有的偶数行给予显示,行前要显示行号;
#!/bin/bash#if [ $# -lt 1 ]; then echo " must ernter /path/to/somefile " exit 1fij=$(wc -l $1 | cut -d" " -f1 )if [ -f $1 ]; then for (( i=1;i<=j ;i++ ));do if [ $[${i}%2] -eq 0 ];then echo -n "$i " head -$i $1 | tail -1 fi donefi