界定程序执行环境;(本质是判定程序是否执行)
(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 变量num2 if [ -z "$num1" ]; then echo "Plz give two integers." exit 1 ##判定第一个参数是否为空 是则提示并退出脚本 fi if [ -z "$num2" ]; then echo "Plz give tow integers." exit 1 ##判定第一个参数是否为空 是则提示并退出脚本 fi if [ $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 <path>" 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 $lockfile if [ $# -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,然后错误结束脚本 fi
case语句
简洁版多分支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 ##提示输入一个字符 用交互方式复制给变量char case $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 $lockfile if [ $# -lt 1 ]; then echo "Usage: $prog start|stop|restart|status" exit 1 fi case $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
循环体
done
LIST:是由一个或多个空格或换行符分隔开的字符串组成;
把列表的每个字符串逐个赋值给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) ##命令引用取得命令执行结果赋值给变量hostname if [ -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=0 declare -i sum2=0 declare -i i=0 while [ $i -le 100 ]; do if [ $[${i}%2] -eq 0 ]; then let sum1+=$i else let sum2+=$i fi let i++ done echo "qishu sum $sum2" echo "oushu sum $sum1"
示例:打印九九乘法表
#!/bin/bash # declare -i i=1 declare -i j=1 while [ $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=0 declare -i sum2=0 declare -i i=0 until [ $i -gt 100 ]; do if [ $[${i}%2] -eq 0 ]; then let sum1+=$i else let sum2+=$i fi let i++ done echo "qishu sum $sum2" echo "oushu sum $sum1"
练习2:实现九九乘法表;
#!/bin/bash # #!/bin/bash # declare -i i=1 declare -i j=1 until [ $i -gt 9 ]; do until [ $j -gt $i ]; do echo -n "${j}x${i}=$[$j*$i] " let j++ done let j=1 let i++ echo done
练习3:分别使用while和until循环实现添加10个用户:user1-user10;
#!/bin/bash # declare -i i=1 while [ $i -le 10 ]; do useradd user${i} let i++ done
#!/bin/bash # declare -i i=1 until [ $i -gt 10 ];do useradd user${i} let i++ done
循环控制:
continue [n]:提前结束本轮循环,而直接进入下一轮;
break [n]:提前结束循环;
while循环:
while CONDITION; do
.......
if CONDITION2; then
break [n]
fi
done
while 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
done
until 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=$1 if [ $# -lt 1 ]; then echo "At lease one argument." exit 1 fi if ! id $username &> /dev/null; then echo "No such user." exit 2 fi until who | grep "^$username" &> /dev/null; do let count++ echo "$count $username is not login." sleep 3 done echo "$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
循环体
done
expr1: 定义控制变量,并初始赋值;
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 echo done
练习2:传递一个文本文件为参数给脚本,取出此文件的所有的偶数行给予显示,行前要显示行号;
#!/bin/bash # if [ $# -lt 1 ]; then echo " must ernter /path/to/somefile " exit 1 fi j=$(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 done fi