bash高级进程

bash脚本编程:

  过程式编程语言
      顺序执行   
      选择执行   
      循环执行   
  循环执行:必须有进入条件和退出条件  
  • 函数:结构化编程及代码重用

    function

选择执行:

if 判断条件;then   
    条件为真的分支代码   
fi   
    
if 判断条件;then
    添加为真的分支代码
else 
    条件为假的分支代码
fi


eg:    
    新建用户
    #!/bin/bash
    ## 如果脚本参数小于1,则退出   
    if [ $# -lt 1 ];then
        echo "At least one argument"
        exit 1
    fi

    ## 判断$1用户是否存在,用户不存在则创建  
    if id $1 &> /dev/null;then
        echo "$1 exists"
        exit 0
    else 
        useradd $1
        [ $? -eq 0 ] && echo "$1" | passwd --stdin $1 &> /dev/null || exit 1 
    fi 

多分支

if  判断条件 1 ; then
    条件为真的分支代码
elif  判断条件 2 ; then
    条件为真的分支代码
elif  判断条件 3 ; then
    条件为真的分支代码
else
    以上条件都为假的分支代码
fi
  • 逐条件进行判断,第一次遇为“真”条件时,执行其分支,而后结束整个if

循环

  • 循环执行
将某代码段重复运行多次
重复运行多少次:
    循环次数事先已知
    循环次数事先未知
    有进入条件和退出条件
  • for, while, until

for循环语法:

  for  NAME in LIST;do 
      循环体   
  done
  • 执行机制
    依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体;直到列表中的元素耗尽,循环结束

  • 循环列表生成方式:

(1)直接给出列表
(2)整数列表   
    {start..end}
    $(seq [start [step]]end)
(3)glob(统配路径下的所有文件)如:*.sh
    /etc/rc.d/rc3.d/k*
(4)返回列表的命令
    $(COMMAND)
(5)变量引用:
    $@,$*

eg:

通过ping命令探测172.17.250.1-254范围内的所有主机的在线状态    
#!/bin/bash 
net='172.17.253'
uphost=0
downhost=0
for i in {1..20};do
    ping -c 1 -v 1 ${net}.$i &> /dev/null
    if [ $? -eq 0 ];then
        echo "${net}.$i is up"
        let uphost++
    else 
        echo "${net}.$i is down"
        let downhost++
    fi
done 
echo "Up host:$uphost"
echo "Down host:$downhost"

while循环:

while CONDITON;do
    循环体
done

CONDITION:循环控制列表:进入循环之前,先做一次判断;每一次循环之后会再次做判断    
    条件为“true”,则执行一次循环:直到条件测试状态为“false”终止循环;
    因此:CONDITION一般应该有循环控制变量,而此变量的值会在循环体不断的被修正
进入条件:CONDITION 为true
退出条件:CONDITION 为false

示例

1 . 求100以内所有正整数之和

declare -i sum=0
declare -i i=1

while [ $i -le 100 ];do
    let sum+=$i
    let i++
done

echo "i=$i"
echo "Summary:$sum"

2 . 添加10个用户

declare -i i=1
declare -i users=0
while [ $i -le 1 ];do
    if ! id user$i &> /dev/null;then
        useradd user$i
        echo "Add user:user$i"
        let users++
    fi
    let i++
done
echo "Add $users users"

3 . 通过ping命令探测172.17.253.1-254范围的所有主机的在线状态:(用while循环)

declare -i i=1
declare -i uphosts=0
declare -i downhosts=0
net='172.17.253'

while [ $i -le 20 ];do
    if ping -c 1 -w 1 $net.$i &> /dev/null;then 
        echo "$net.$i is up"
        let uphosts++
    else 
        echo "$net.$i is downhosts"
        let downhosts++
    fi 
    let i++
done 
echo "Up hosts:$uphosts"
echo "Down host:$downhosts"

4 . 打印九九乘法表:(分别使用for和while循环实现)

for语句

    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

while语句   

    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

5 . 利用RANDOM生成10个随机数字,输出这10个数字,并显示其中的最大值和最小值

#!/bin/bash
declare -i max=0
declare -i min=0
declare -i i=1

#max=$rand
#min=$rand 

while [ $i -le 9 ];do
    rand=$RANDOM
    echo $rand

    if [ $i -eq 1 ];then
        max=$rand
        min=$rand
    fi
    if [ $rand -gt $max ];then 
        max=$rand
    fi
    if [ $rand -lt $min ];then
        min=$rand
    fi
    let i++
done  

echo "MAX:$max"
echo "MIN:$min"

unil

unil COMDITION;do
    循环体
done
循环条件为:false
退出条件为:true

示例

1 . 求100以内所有正整数之和

/bin/bash
#!
declare -i i=1
declare -i sum=0

until [ $i -gt 100 ];do
    let sum+=$i 
    let i++
done
echo "Sum:$sum" 

2 . 打印九九乘法表

#!/bin/bash
# filename timetale3.sh
# author:danran 
# time is 2017-06-22
declare -i j=1
declare -i i=1

until [ $j -gt 9 ];do
    until [ $i -gt $j ];do
        echo -n -e "${i}X${j}=$[$i*$j]\t"
        let i++
    done
    echo 
    let i=1
    let j++
done 

循环控制语句(用于循环体中)

continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断
    while CONDTITION1;do
        CMD1
        ...
        if CONDITION;then
            continue
        fi
        CMDn
        ...
    done




break [N]:提前结束循环
break [N] :提前结束第N 层循环,
    while CONDTITION1;do
        CMD1
        ...
        if CONDITION;then
            break
        fi
        CMDn
        ...
    done

示例

求100以内所有偶数之和,要求循环遍历100以内的所有正整数

#!/bin/bash
# filename even.sh
# author:danran 
# time is 2017-06-22

declare -i i=0
declare -i sum=0
until [ $i -gt 100 ];do
    let i++
    if [ $[i%2] -eq 1 ];then
        continue
    fi
    let sum+=$i
done
echo "Even sum:$sum"

创建死循环

while true;do
    循环体
done

until false;do
    循环体
done

示例

每隔3秒钟到系统上获取已经登录的用户的信息:如果docker登录了,则记录于日志中,并退出

read -p "Enter a user name: " username

while true;do
    if who | grep "^$username" &> /dev/null;then
        break
    fi
    sleep 3
done
echo "$username logged on" >> /tmp/user.log

法二
#!/bin/bash
#
read -p "Enter a user name: " username

until who | grep "^$username" &> /dev/null;do
    sleep 3
done
echo "$username logged on" >> /tmp/user.log

练习

写一个脚本:完成如下任务:

(1)显示一个菜单   
    cpu)show cpu information:
    mem)show memory information
    disk)show disk information quit)quit
(2)提示用户选择选项     
(3)显示用户选择的内容    
进一步的:
    用户选择,并显示完成后不退出脚本;而是提示用户继续选择显示其内容:直到使用quit方始退出;

法一    
#!/bin/bash
# filename sysinfo.sh
# author:danran 
# time is 2017-06-22
cat << EOF
cpu) show cpu information
mem) show memory information
disk)show disk information 
quit)quit
============================
EOF

read -p "Enter a option: " option
while [ "$option" != 'cpu' -a "$option" != 'mem' -a "$option" != 'disk' -a "$option" != 'quit' ];do
    read -p "Wrong option.Enter again: " option
done

if [ "$option" == 'cpu' ];then
    lscpu
elif [ "$option" == 'mem' ];then
    cat /proc/meminfo
elif [ "$option" == 'disk' ];then
    fdisk -l
else 
    echo "Quit"
    exit 0
fi

条件判断:case语句

case 变量引用 in
PAT1)
    分支1
    ;;
PAT2)
    分支2
    ;;
...
*)
    默认分支
    ;;
easc
  • case 支持glob 风格的通配符:
*:任意长度任意字符
?:任意单个字符
[]:指定范围内的任意单个字符
a|b:a或b  

法二

#!/bin/bash
# filename sysinfo.sh
# author:danran 
# time is 2017-06-22
cat << EOF
cpu) show cpu information
mem) show memory information
disk)show disk information 
quit)quit
============================
EOF

read -p "Enter a option: " option
while [ "$option" != 'cpu' -a "$option" != 'mem' -a "$option" != 'disk' -a "$option" != 'quit' ];do
    read -p "Wrong option.Enter again: " option
done

case "$option" in
cpu)
    lscpu
    ;;
mem)
    cat /proc/meminfo
    ;;
disk)
    fdisk -l
    ;;
*)
    echo "Quit.."
    exit 0
    ;;
esac

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

(1)脚本可接受参数,start,stop,restart,status
(2)如果参数非此四者之一,提示使用格式后报错退出
(3)如果是start,则创建/var/lock/subsys/SCRIOT_NAME,并显示“启动成功”
    考虑:如果事先已经启动过一次,该如何处理
(4)如果是stop:则删除/vat/lock/subsys/SCRIPT_NAME,并显示“停止完成”
    考虑:如果事先已经停止过了;g该如何处理
(5)如果是restart,则先stop,再start;
    考虑:如果本来没有start,再如何处理   
(6)如果是status,则
    如果/var/lock/subsys/SCRIPT_NAME文件存在,则显示“SCRIPT_NAME is running...”;
    如果/var/lock/subsys/SCRIPT_NAME文件不存在,则显示“SCRIPT_NAME is stopped...”;
其中:SCRIPT_NAME为当前脚本名  

循环控制shift命令

shift [n]

用于将参量列表list 左移指定次数,缺省为左移一次。

  • 参量列表list一旦被移动,最左端的那个参数就从列表中删除。while到循环遍历位置参量列表时,常用到shift
  • ./doit.sh a b c d e f g h
  • ./shfit.sh a b c d e f g h

示例:

doit.sh
    #!/bin/bash
    # Name:doit.sh
    # Purpose:shift through command line arguments
    # Usage:doit.sh [args]
    while [ $# -gt 0 ] # or (( $# > 0 ))
    do
        echo $*
        shift
    done

shift.sh
    #!/bin/bash
    #step through all the positional parameters
    until [ -z "$1" ]
    do
        echo "$1"
        shift
    done
    echo

特殊用法

  • while 循环的特殊用法(遍历文件的每一行):
while read line; do
    循环体
done < /PATH/FROM/SOMEFILE
  • 依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line
  • 练习
    扫描/etc/passwd文件每一行,如发现GECOS 字段为空,则填充用户名和单位电话为62985600,并提示该用户的GECOS信息修改成功。
  • 示例:
#!/bin/bash
while read passwdline
do
    uid=`echo $passwdline | cut -d: -f3`
    user=`echo $passwdline | cut -d: -f1`
    [ "uid" -ge 1000 ] && echo "$user is common user" || echo "$user is system user"
done < /etc/passwd
unset passwdline uid user
  • 双小括号方法,即((…))格式,也可以用于算术运算
  • 双小括号方法也可以使bash Shell 实现C 语言风格的变量操作
I=10
((I++))
  • for循环的特殊格式:
for (( 控制变量初始化; 条件判断表达式; 控制变量的修正表达式))
do
    循环体
done
  • 控制变量初始化:仅在运行到循环代码段时执行一次
  • 控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断
  • 示例:求100以内的所有正奇数之和
#!/bin/bash
sum=0
for i in {1..100..2};do
    let sum+=i
done
echo sum=$sum

#!/bin/bash
for ((sum=0,i=1;i<=100;i+=2 ));do
    let sum+=i
done
echo sum=$sum

#!/bin/bash
sum=0;
i=1;
while [ $i -le 100 ];do
    let sum+=1
    let i+=2
done
echo sum=$sum

2 . 求100以内的正整数之和

#!/bin/bash
declare -i sum=0
for ((i=1;i<=100;i++));do
    let sum+=$i
done
echo "Sum:$sum"

3 . 打印九九乘法表:

#!/bin/bash
# filename multi.sh
# author:danran 
# time is 2017-06-22
for ((j=1;j<=9;j++));do
    for((i=1;i<j;i++));do
        echo -e -n "$[i]X$[j]=$[$i*$j]\t"
    done
    echo
done

select循环与菜单

select variable in list
do
    循环体命令
done
  • select循环主要用于创建菜单,按数字顺序排列的示菜单项将显示在标准错误上,并显示PS3提示符,等待用户输入
  • 用户输入菜单列表中的某个数字,执行相应的命令
  • 用户输入被保存在内置变量REPLY中

select与case

  • select用是个无限循环,因此要记住用 break命令退用出循环,或用exit按命令终止脚本。也可以按ctrl+c退出循环
  • select和经常和case联合使用
  • 与for循环类似,可以省略inlist,此时使用位置参量
  • 示例:创建菜单
#!/bin/bash
PS3="Please choose your menu: "
select menu in work home office exit 
do
    case $menu in 
    work)
        echo "go work"
        ;;
    home)
        echo "go home"
        ;;
    office)
        echo "go office"
        ;;
    *)
        echo unknow
        break
    esac
    echo your choose is $menu
    echo "Your input is $REPLY"
done

信号捕捉trap

  • trap ' 触发指令' 信号
    自定义进程收到系统发出的指定信号后,将执行触发指令,而不会执行原操作
  • trap '' 信号
    忽略信号的操作
  • trap '-' 信号
    恢复原信号的操作
  • trap -p
    列出自定义信号操作

trap示例

#!/bin/bash
trap 'echo “signal:SIGINT"' int
trap -p  \\打印trap自定义命令
for((i=0;i<=10;i++))
do
    sleep 1
    echo $i
done

trap '' int  //int信号设置为空
trap -p   \\打印trap自定义命令
for((i=11;i<=20;i++))
do
    sleep 1
    echo $i
done

trap '-' int  //恢复int信号的操作
trap -p   \\打印trap自定义命令
for((i=21;i<=30;i++))
do
    sleep i
    echo $i
done
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容

  • 流程控制过程式编程语言:顺序执行选择执行循环执行 一.条件选择if语句 类型:选择执行 注意:if语句可嵌套 ...
    楠人帮阅读 477评论 0 1
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,505评论 18 399
  • Bash内置基本变量 PWD : 显示当前的工作目录 OLDPWD : 显示上一次的工作目录 ~:用户家目录 - ...
    魏镇坪阅读 1,505评论 0 6
  • 早起的鸟儿有食吃。2017已经过去四分之一,不知道大家的目标实现了多少呢?无论是相对稳定的上班一族,还是自由职业为...
    奋斗的番茄阅读 159评论 0 0
  • 淅淅沥沥的雨 雨天 有人说找个咖啡店 靠窗坐 手托着下巴 眼睛望向窗外 看着窗户上划过的雨痕 觉得发呆也很幸福 而...
    南宫紫雪阅读 226评论 0 0