Shell脚本应用及循环语句 一.bash通配符: 1. ?//任意的单个字符 2.*//0个或多个字符 3. [] //区间内的任意一个字符 4.; //分割命令,忽略前一个命令的执行结果,继续执行后面的命令 5.& //后台执行程序 6.&& //前面的命令执行成功,返回值是0,执行后面的命令。 7.|| //前面的命令执行失败,返回值非0,执行后面的命令。 8. | //管道 9.() //开启子shell,执行里面的命令 10.{} //里面的命令在当前shell执行 11.> >> //输出重定向 12.< << //输入重定向 13.$ //定义变量 14.\ //转义;命令的折行 15.`` //调用命令的执行结果;不可以嵌套 16 .- //连字符;命令的选项的前导, - -- 17. '' //强引用符号;屏蔽特殊字符 18."" //弱引用符号;`` $ \ 这3个符号屏蔽不了 19.: //表示空操作,返回值永远是0;while循环 20. [:alnum:]//字母+数字 21[:alpha:] //字母 22[:lower:]//小写字母 23[:upper:] //大写字母 24[:digit:] //十进制数 25 [:punct:] //符号 26 [:space:]//空白字符(空格 “tab”) 27 [[:alnum:]] //任意的一个字母或数字[a-Z0-9] 28 [^[:alnum:]] //取反 [[:alnum:]!] 二. 变量 1.注意 (1)=的两边千万不要有空格 (2)不要使用$作为变量的名字 (3)变量名的长度--256个字符,区分大小写 2.如何引用 (1)直接引用: echo 命令 -e :启用\(反斜线)控制字符(\t \n)的转换 -n :取消换行符 [root@tx1 ~]# echo "123\t234" 123\t234 [root@tx1 ~]# echo -e "123\t234" 123 234 [root@tx1 ~]# echo -e "123\n234" 123 234 [root@tx1 ~]# echo -n "123\t234" 123\t234[root@tx1 ~]# (2)间接引用 [root@tx1 ~]# a=b [root@tx1 ~]# b=c [root@tx1 ~]# echo $a b [root@tx1 ~]# echo ${!a} c (3)变量的作用域 @1在当前的shell里,定义的变量叫做本地变量-局部变量。 @2全局变量-环境变量,export 把局部变量变成全局变量。只作用于子shell。 [root@tx1 ~]# x=123 [root@tx1 ~]# echo $x 123 [root@tx1 ~]# bash [root@tx1 ~]# echo $x
[root@tx1 ~]# exit exit [root@tx1 ~]# export x [root@tx1 ~]# bash [root@tx1 ~]# echo $x 123
(4)查看定义的变量 @1.set 查看所有的变量 @2.env 查看全局变量 @3.unset 取消变量 unset+变量名 @4.设置变量为只读: readonly+变量名
(5)位置参数$ 注:位置参数,从命令行传递给脚本,或者是传递给函数.或者赋职给一个变量. $0 命令本身 $1 $2 ...... ${10} $# 参数的个数 $* 所有的参数
$@ 所有的参数(需要被” ” 引用) $$ 上一条命令的进程号 $? 上一条命令的返回结果 $_ 上一条命令的最后一个参数 $! 最后一个进入后台的命令的进程号 $() 等同于`` $(()) 等同于$[] 做数学运算的,但是只能算整数 (6)变量的置换 注:用来执行匹配或者是判断变量是否存在。 @1.${变量名:-字符串}:如果变量是空的,那么就返回字符串;否则返回变量的值 @2.${变量名:+字符串}:如果变量有值,那么使用字符串替换变量;否则返回空值 @3.${变量名:=字符串}:如果变量没有值,那么就把字符串赋值给变量;否则返回变量的值
@4.${变量名:?提示信息}:如果变量没有值,那么返回提示信息 @1. [root@tx1 ~]# echo $a [root@tx1 ~]# echo ${a:-123} 123 [root@tx1 ~]# b=abc [root@tx1 ~]# echo ${b:-123} Abc
@2. [root@tx1 ~]# echo ${a:+123} [root@tx1 ~]# echo ${b:+123} 123
@3. [root@tx1 ~]# echo $a [root@tx1 ~]# echo $b abc [root@tx1 ~]# echo ${a:=123} 123 [root@tx1 ~]# echo $a 123 [root@tx1 ~]# echo ${b:=123} abc [root@tx1 ~]# echo $b Abc
@4. [root@tx1 ~]# unset a [root@tx1 ~]# echo ${a:?} bash: a: parameter null or not set [root@tx1 ~]# echo ${a:?没有设置变量} bash: a: 没有设置变量 (7)变量的匹配模式 #:从变量的值的头部开始最小匹配,然后删除 ## :从变量的值的头部开始最大匹配,然后删除 % :从变量的值的尾部开始最小匹配,然后删除 %% :从变量的值的尾部开始最大匹配,然后删除 :num1:num2 :截取变量的值,num1是开始的位置,num2是截取出来几位;0是第一个字符 @1. [root@tx1 ~]# echo ${pth#*/} usr/bin/local/bin/all [root@tx1 ~]# echo ${pth##*/} all @2. [root@tx1 ~]# echo ${pth%/*} /usr/bin/local/bin [root@tx1 ~]# echo ${pth%%/*}
[root@tx1 ~]# @3. [root@tx1 ~]# echo ${pth:0:6} /usr/b [root@tx1 ~]# echo ${pth:3:6} r/bin/ 三.If语句 1.单分支if语句. if [ 条件表达式 ]; then 命令;... fi 注:条件满足的时候,就会运行then后面的语句,不满足就直接退出判断语句
2.双分支if语句 if [ 条件表达式 ];then 命令;... else 命令;... fi 注:等条件满足的时候就会运行then后面的语句,条件不满足的时候就运行else后面的语句。 3.条件表达式(man test) (1)字符串的判断 str1 = str2 检查str1与str2是否相同 str1 != str2 检查str1与str2是否不同 str1 < str2 检查str1是否小于str2 str1 > str2 检查str1是否大于str2 -n str1 检查str1的长度是否大于0 -z str1 检查str1的长度是否为0 =~:判断左边的字符串是否能够被右边的模式所匹配,[[ "$opt1" =~ pattern ]], 注:判断字符串的时候,字符串要用""包起来(更详细的man test)
(2)整数的判断 -eq 等于 -ge 大于等于 -gt 大于 -le 小于等于 -lt 小于 -ne 不等于 (3)文件的判断 -b file 判断是否存在且为块文件 -c file 判断是否存在且为字符文件 -d file 判断是否存在且为目录文件 -e file 判断文件是否存在 -f file 判断文件是否存在且为一个普通文件 -h file 判断是否存在且为符号链接 -r file 判断是否存在且可读 -s file 判断是否存在且不为空 -w file 判断是否存在且可写 -x file 判断是否存在且可执行 -O file 判断是否存在且用户为当前用户 -G file 判断是否存在且组为当前组
(4)条件语句 与 -a if [ 表达式1 -a 表达式2 ]
或 -o if [ 表达式1 -o 表达式2 ]
非 ! if [ ! 表达式 ] 注 [[ 表达式1 && 表达式2 ]] == -a [[ 表达式1 || 表达式2 ]] == -o [[ ! 表达式 ]] == ! if 表达式 then command elif 表达式 then command elif 表达式 then command ...... else command fi
(5)多重判断
例1. 注:read -p -t 超时时间 -t 3(秒) -s 输入没有回显,(密码) [root@tx1 ~]# vim tx1.sh #!/bin/bash #这是一个判断文件类型的脚本 if [ -b /dev/hda1 ] then echo "块设备" fi
if [ -d /etc ] then echo "目录" fi if [ -e /etc/passwd ] then echo "普通文件"
fi [root@tx1 ~]# ./tx1.sh 块设备 目录 普通文件 例2 #!/bin/bash #这是一个判断用户是否存在的脚本
read -p "请输入一个用户名:" uname if [ "$uname" = "" ] then echo "error" else if grep "^\<$uname\>" /etc/passwd &> /dev/null then echo "这个用户存在" else echo "这个用户不存在" fi fi 例3(if的嵌套) 注:为终端加密 [root@tx1 ~]# vim /etc/bashrc read -p "请输入用户名:" uname if [ "$uname" = "root" ] then read -p "请输入密码:" pass if [ "$pass" = "123" ] then echo "welcome root" else exit 1 fi else exit 2 fi 打开一个新的终端后 请输入用户名:root 请输入密码:123 welcome root [root@tx1 ~]# 例4 #!/bin/bash # 使用双重条件判断用户名和密码 read -t 5 -p "username: " uname read -s -p "password: " pass echo
if [ "$uname" = "root" -a "$pass" = "123" ] then echo "welcome root" else echo "go out" fi 例5 #!/bin/bash #判断一个用户的类型 read -p "请输入一个用户名:" uname id=`grep "^\<$uname\>" /etc/passwd | cut -d : -f 3 ` if [ "$uname" = "" ] then echo "error" elif [ $id -ge 500 ] then echo "$uname 是普通用户" elif [ $id -lt 500 -a $id -ge 1 ] then echo "$uname 是系统用户" else echo "$uname 是超级用户" fi [root@tx1 ~]# ./tx5.sh 请输入一个用户名:root root 是超级用户 [root@tx1 ~]# ./tx5.sh 请输入一个用户名:tx tx 是普通用户 [root@tx1 ~]# ./tx5.sh 请输入一个用户名:bin bin 是系统用户 [root@tx1 ~]# ./tx5.sh 请输入一个用户名: error 四.case 多分支判断 语法: case $变量 in value1) commands ;; value2) commands ;; ...... *) commands ;; esac 例1. 注:例如人的年龄: 0 婴儿 ,1-9 幼儿,1-19 少年,20-29 青年,30-39 中年,40-老年 #!/bin/bash # 判断人的年龄段 read -p "请输入一个人的年龄:" age case $age in 0) echo "婴儿" ;; [1-9]) echo "幼儿" ;; 1[0-9]) echo "少年" ;; 2[0-9]) echo "青年" ;; 3[0-9]) echo "中年" ;; *) echo "老年" ;; esac [root@tx1 ~]# ./t1.sh 请输入一个人的年龄:3 幼儿 [root@tx1 ~]# ./t1.sh 请输入一个人的年龄:67 老年 [root@tx1 ~]# ./t1.sh 请输入一个人的年龄:20 青年
五.For循环
注:for循环 事先提供一个元素列表,而后,使用变量去遍历此元素列表,每访问一个元素,就执行一次循环体,直到元素访问完毕 for 变量 in 变量列表 do commands done 例1. 用for循环输出三个数 #!/bin/bash for i in "$*" do echo $i done
for j in "$@" do echo $j done [root@tx1 ~]# ./t3.sh 1 2 3 1 2 3 1 2 3 例2.把 /usr/share/doc/ 下所有的index.html复制到 /tmp/index/目录下,/tmp/index/ 不确定是否存在。 #!/bin/bash if [ -d /tmp/index ] then num=1 for i in $(find /usr/share/doc -name index.html) do /bin/cp $i /tmp/index/index.html.$num num=$(($num+1)) done else mkdir /tmp/index num=1 for i in $(find /usr/share/doc -name index.html) do /bin/cp $i /tmp/index/index.html.$num num=$(($num+1)) done fi 六.While语句 语法: while [ 表达式 ] do commands 更新表达式 done
表达式的作用:判定循环是否执行。 表达式的返回值为真, $?=0,执行命令 表达式的返回值是假的,结束循环。 : ;true 返回值永远是真的。 例1.批量创建5个用户 [root@tx1 ~]# cat t1.txt tx1 tx2 tx3 tx4 tx5 [root@tx1 ~]# cat t6.sh #!/bin/bash while read line do uname=`echo $line` useradd $uname echo $uname | passwd $uname --stdin done < /root/t1.txt 例2.信号捕捉 注:信号捕捉,trap,1 2 9 15 ,信号9是捕捉不了的。 #!/bin/bash #信号捕捉
trap "echo 进程还在继续" 1
while : do echo "hello" sleep 3 done [root@tx1 ~]# ps -a PID TTY TIME CMD 18810 pts/2 00:00:00 bash 18813 pts/2 00:00:00 sleep 18814 pts/1 00:00:00 ps [root@tx1 ~]# kill -1 18810
[root@tx1 ~]# ./t7.sh hello hello hello hello 进程还在继续 hello 七.Until语句 语法: until [ 表达式 ] do commands 更新表达式 done
表达式的作用:判定循环是否执行。 表达式的返回值为假的时候,执行循环,$? 非0 表达式的返回值为真的时候,结束循环 例1. #!/bin/sh
a=10; until [[ $a -lt 0 ]];do echo $a; ((a--)); done; [root@tx1 ~]# ./t8.sh 10 9 8 7 6 5 4 3 2 1 0 八.shift,break和continue 例1 #!/bin/bash until [ $# -eq 0 ] do echo $* shift done [root@tx1 ~]# ./tt1.sh 1 2 3 4 5 6 1 2 3 4 5 6 2 3 4 5 6 3 4 5 6 4 5 6 5 6 6 例2.break跳出循环 #!/bin/bash for i in `seq 1 2` do for j in `seq 1 3` do echo $j if [ $j -eq 2 ] then break #跳出当前循环 fi done done [root@tx1 ~]# ./tt2.sh 1 2 1 2
例3 #!/bin/bash for i in `seq 1 10` do for j in `seq 1 3` do echo $j if [ $j -eq 2 ] then break 2 #跳出第2层循环 fi done done [root@tx1 ~]# ./tt3.sh 1 2 例4 (continue结束本次循环) #!/bin/bash for i in `seq 1 3` do for j in `seq 1 3` do if [ $j -eq 2 ] then continue #结束本次循环 fi echo $j done done [root@tx1 ~]# ./tt4.sh 1 3 1 3 1 3 例5 #!/bin/bash for i in `seq 1 3` do for j in `seq 1 3` do if [ $j -eq 2 ] then continue 2 #结束第2层的本次循环 fi echo $j done done
[root@tx1 ~]# ./tt5.sh 1 1 1 |