AI智能
改变未来

shell的几个重要命令,主要参数,循环语句以及变量处理

======================================================================
ule-scripts-shell
======================================================================

———————————————————————-
shell02
———————————————————————-

:尚观科技: http://uplooking.com

.. contents::
.. sectnum::

shell中重要的几个内部命令
———————————————————————-

* eval <args>       # 把后面的args当作一行命令来执行
* exec <args>       # 后面跟命令作为参数, 它不会去创建新的子进程, 也就是说, 它结束后, 脚本就结束了, 不会再执行exec后面的语句了!!

|    [nich4@server4 ~]$ cat a.sh
|    #!/bin/sh
|    #
|    echo aaaa
|    exec \’ls\’
|    echo bbbb
|    [nich4@server4 ~]$ chmod +x a.sh
|    [nich4@server4 ~]$ ./a.sh
|    aaaa
|    a.sh
|    [nich4@server4 ~]$

* readonly      # 定义一个只读变量, 当前shell中不可更改,不可unset
 
    可以先定义变量var, 再执行readonly var

    也可以直接执行readonly var=value

* read      # 可以一次要求输入多个变量, 由空格分隔

|    [root@localhost nich4]# read a b c d e
|    1 2 3 4 5
|    [root@localhost nich4]# echo $a $b $c $d $e
|    1 2 3 4 5
|    [root@localhost nich4]#

* wait      # 使Shell等待在后台启动的所有子进程结束。wait的返回值总是真
* exit      # 退出Shell程序。在exit之后可有选择地指定一个数作为返回状态
* shift     # 按下面的方式重新命名所有的位置参数变量,即$2成为$1,$3成为$2…在脚本中每使用一次shift语句,都使所有的位置参数依次向左移动一个位置,并使位置参数$#减1,直到减到0为止
* .         # 点.  让shell读入指定的脚本文件, 并依次执行那个脚本中的语句, (即把脚本调入到当前shell中来执行)
* :         # : 空命令 NOP no op 相当于true,返回0

bash程序的调试
———————————————————————-

在编程过程中难免会出错,有的时候,调试程序比编写程序花费的时间还要多,Shell程序同样如此。

Shell程序的调试主要是利用bash命令解释程序的选择项。调用bash的形式是:

>> bash <参数> file

几个常用的选择项是:

-e 如果一个命令失败就立即退出。

-n 读入命令但是不执行它们。

-u 执行时把未设置的变量看做出错。

-v 当读入Shell命令时把它们显示出来。

-x 执行命令时把命令和它们的参数显示出来。

上面的所有选项也可以在Shell程序内部用\”set -<>\”的形式引用,而\”set +<>\”则将禁止该选择项起作用。如果只想对程序的某一部分使用某些选择项时,则可以将该部分用上面两个语句包围起来。

(1) 未置变量退出和立即退出

未置变量退出特性允许用户对所有变量进行检查,如果引用了一个未赋值的变量就终止Shell程序的执行。Shell通常允许未置变量的使用,在这种情况下,变量的值为空。如果设置了未置变量退出选择项,则一旦使用了未置变量就显示错误信息,并终止程序的运行。未置变量退出选择项为-u。

当Shell运行时,若遇到不存在或不可执行的命令、重定向失败或命令非正常结束等情况时,如果未经重新定向,该出错信息会显示在终端屏幕上,而Shell程序仍将继续执行。要想在错误发生时迫使Shell程序立即结束,可以使用-e选项将Shell程序的执行立即终止。

(2) Shell程序的跟踪

调试Shell程序的主要方法是利用Shell命令解释程序的-v或-x选项来跟踪程序的执行。-v选择项使Shell在执行程序的过程中,把它读入的每一个命令行都显示出来,而-x选择项使Shell在执行程序的过程中把它执行的每一个命令在行首用一个+加上命令名显示出来。并把每一个变量和该变量所取的值也显示出来。因此,它们的主要区别在于:在执行命令行之前无-v,则显示出命令行的原始内容,而有-v时则显示出经过替换后的命令行的内容。

除了使用Shell的-v和-x选择项以外,还可以在Shell程序内部采取一些辅助调试的措施。例如,可以在Shell程序的一些关键地方使用echo命令把必要的信息显示出来,它的作用相当于C语言中的printf语句,这样就可以知道程序运行到什么地方及程序目前的状态。

shell命令替换与扩展
———————————————————————-

* *命令替换* 很简单, 就两种情况: $( ) 和 \\` \\`

* *路径扩展:* 通配符 \\* ? [] {}

.. note::

    花括号{}和中括号[]: 可以生成列表(list),其中\\*号以逗号分隔.[]不需要分隔

    特殊的: {1..10}     # 生成1到10的序列, 类似的还有\”seq 1 10\”

shell参数
———————————————————————-

* 位置参数: 脚本运行时传给脚本的参数   $1, $2 ,… ${10}, ${100}
* 内部参数:

|    $#    # 参数个数
|    $*    # 所有参数的字符串
|    $@    # 所有参数, 每个参数为一个字符串
|    $?    # 上一条命令执行后的返回值
|    $$    # PID
|    $0    # 当前shell的名字

分支语句 流程控制
———————————————————————-

if语句
“““““““““““““““““““““““““““““““““““

::

    if [ condition ];then
        command
    fi
    ———————
    if [ condition ];then
        command
    else
        command
    fi
    ———————
    if [ condition ];then
        command
    elif [ condition ];then
        command
    else
        command
    fi
    ———————-
    if [ condition ];thne
        command
        command
        if [ condition ];then
            command
        fi
    else
        if [ condition ];then
            command
        elif [ condition ];then
            command
        else
            command
        fi
    fi  

case语句
“““““““““““““““““““““““““““““““““““

*标准用法:*

::

    case \”$arg\” in
        arg1 | arg01)   # | 或者
            cmd
            ;;
        arg2)
            cmd
            ;;
        *)
            cmd
            ;;
    esac
        
**eg:**

::

    case $1 in  
            start | begin)  
              echo \”start\”  
            ;;  
            stop | end)  
              echo \”stop\”  
            ;;  
            \\*)  
              echo \”Ignorant\”  
            ;;  
    esac

**eg:** 判断系统
    
有时候,我们需要写跨平台的脚本, 那么我们就需要判断一下脚本运行在什么平台, 然后再使用相应的方法来实现,如Linux、FreeBSD、Solaris等等::

    #!/bin/sh  
    SYSTEM=`uname -s`  
    
    case \”$SYSTEM\” in  
        Linux)  
            echo \”My system is Linux\”  
            echo \”Do Linux stuff here…\”  
        ;;  
        FreeBSD)  
            echo \”My system is FreeBSD\”  
            echo \”Do FreeBSD stuff here…\”  
        ;;  
        *)  
            echo \”Unknown system : $SYSTEM\”  
            echo \”I don\’t what to do…\”  
        ;;  
    esac

.. note::

    case语句的匹配是从上往下的顺序, 因此我们编写的原则也是从上往下

    case语句的模板支持匹配: * ? []

    * 匹配以n开头的所有情况: n*
    * 匹配yes的所有字母大小不同的情况: [yY][eE][sS]
    * 但不支持{}匹配,因为可以使用 | 就可以达到目的。

循环语句
———————————————————————-

for循环
“““““““““““““““““““““““““““““““““““

标准用法:

::
    
    for xx  in xx xxx xx
    do
        command
    done

    for (( i=0 ; i<5 ; i++ ))     #   定义一个变量,i<5 循环的退出条件,i++ 代表自加1
    do
        command;
        command;
    done

    for (( i=30 ; i>0 ; i– ))     #   定义一个变量,i<5 循环的退出条件,i++ 代表自加1
    do
        command;
        command;
    done

while循环
“““““““““““““““““““““““““““““““““““

实现如果不确定循环的次数,这时候就要用到while

标准用法:

::

    while [ condition ]  # 只要条件满足就继续循环
    do
        command
    done

until循环
“““““““““““““““““““““““““““““““““““

当满足条件的时候,退出循环, 而while是不满足条件的时候才退出循环.

::
    
    until [ condition ] ; do
        command;
        command;
        …
        command;
    done

    eg:

    $ VAR=10
    $ until [ \”$VAR\” -eq 0 ]; do
    >   echo $VAR;
    >   VAR=$(($VAR-1));
    > done

    eg:

    rannum=`expr $RANDOM % 101`
    small=0
    big=100

    read -p \”Input you guest:\” guest

    until [ \”$rannum\” -eq \”$guest\” ]  # $rannum = $guest 的时候就退出循环
    do
        [ … ] && command

    done

select
“““““““““““““““““““““““““““““““““““

select 多用来快速的设计一个字符界面的用户交互选择的菜单, 也多与case一起使用.

语法和 for 循环非常相似:

::

    select Key in List
    do
        Command;
    done

    eg:

    #!/bin/sh
    #

    echo \”请选择:\”
    list=\”Success Fail Exit\”

    select a in $list;do
        if [ \”$a\” = \”Success\” ];then
            echo Success
        elif [ \”$a\” = \”Fail\” ];then
            echo Fail
        elif [ \”$a\” = \”Exit\” ];then
            exit
        else
            echo \”No the Choose\”
        fi
    done

\”奇技淫巧\”
“““““““““““““““““““““““““““““““““““

::
    
    shell_for_loop总结
    # Modified: 20101012-11:57:31 by [email protected]
    # Filename: loop-example.txt
    
    #!/bin/env bash
    #
    for i in 1 2 3 4 5
    do
        echo \”Welcome $i times\”
    done
    
    
    #/bin/env bash
    # bash version 3.0+
    #
    for i in {1..5}
    for i in $(seq 1 5)
    do
        echo \”Welcome $i times\”
    done
    
    #!/bin/env bash
    # bash version 4.0+
    # {START..END..INCREMENT}
    #
    echo \”Bash version ${BASH_VERSION}…\”
    for i in {0..10..2}
    do
        echo \”Welcome $i times\”
    done
    
    #!/bin/env bash
    #
    for i in `seq 1 2 20`
    do
        echo \”Welcome $i times\”
    done
    
    #!/bin/env bash
    # for (( EXP1; EXP2; EXP3 ))
    #
    for (( c=1; c<=5; c++ ))
    do
        echo \”Welcome $c times…\”
    done
    
    #!/bin/env bash
    # infinite loops
    #
    for (( ; ; ))    # other: 1. while true 2. while :
    do
        echo \”innfinite loops [ hit CTRL+C to stop]\”
    done
    
    #!/bin/env bash
    #
    #for I in 1 2 3 4 5
    #do
    #  statements1      #Executed for all values of \’\’I\’\’, up to a disaster-condition if any.
    #  statements2
    #  if (disaster-condition)
    #  then
    #    break              #Abandon the loop.
    #  fi
    #  statements3          #While good and, no disaster-condition.
    #done
    #
    for file in /etc/*
    do
        if [ \”${file}\” == \”/etc/resolv.conf\” ]
        then
            countNameservers=`grep -c nameserver /etc/resolv.conf`
            echo \”Total ${countNameservers} nameservers defined in ${file}\”
            break
        fi
    done
    
    
    #!/bin/env bash
    #
    #for I in 1 2 3 4 5
    #do
    #  statements1      #Executed for all values of \’\’I\’\’, up to a disaster-condition if any.
    #  statements2
    #  if (condition)
    #  then
    #    continue   #Go to next iteration of I in the loop and skip statements3
    #  fi
    #  statements3
    #done
    #
    FILES=\”$@\”
    for f in $FILES     #打印脚本的参数,此处可省略\”in $FILES\”,只需要\”for f\”
    do
        # if .bak backup file exists, read next file
        if [ -f ${f}.bak ]
        then
            echo \”Skiping $f file…\”
            continue
        fi

        # we are hear means no backup file exists, just use cp command to copy file
        /bin/cp $f $f.bak
    done
    
    #!/bin/env bash
    #
    FILE=/etc/passwd
    FS=\’:\’
    while read line
    do
        # store field 1
        F1=$(echo $line|cut -d$FS -f1)
        # store field 2
        F2=$(echo $line|cut -d$FS -f6)
        # store field
        F3=$(echo $line|cut -d$FS -f7)
        echo \”User \\\”$F1\\\” home directory is $F2 and login shell is $F3\”
    done < $FILE

.. code:: bash
    
    例:

    编写脚本,实现一个闹钟

    #!/bin/bash
    # 定时闹钟
    
    clock=$1
    
    while true
    do
    now=$(date +%H:%M:%S)
            if [ \”$now\” = \”$clock\”  ]
            then
                    echo -e \”$now time\’s up !\”
                    for (( i=0; i<5;i++ ))
                    do
                            echo -e -n \”\\a\”
                            sleep 1
                    done
                    break
            fi
    done

shell变量扩展
———————————————————————-

1. 变量定义与删除

| var_name=value   # 等号前后没有空格
|                  # 字母和数字, 字母开头
| kernel=$(uname -r)
| kernel=`uname -r`
| read var_name
|
| unset var_name

#. 变量引用与显示
| $var_name
| ${var_name}str  # 显示指定, 字符串合并
| echo $var_name

#. 变量处理

需要用{}括起来.

* ${var:-default}     # 如果变量var没有定义, 则临时使用\”default\”值

|    作用: 如果变量未定义,返回一个默认值
|    
|    [nich4@server4 ~]# echo ${var}
|    
|    [nich4@server4 ~]# echo ${var:-default}
|    default
|    [nich4@server4 ~]# echo ${var}
|    
|    [nich4@server4 ~]# var=new
|    [nich4@server4 ~]# echo ${var:-default}
|    new
|    [nich4@server4 ~]#
|    

* ${var:=default}     # 如果变量var没有定义, 则把\”default\”值赋给变量var

|    作用: 如果变量未定义,为变量设初始值,并返回
|    
|    [nich4@server4 ~]$ echo $var
|    
|    [nich4@server4 ~]$ echo ${var:=default}
|    default
|    [nich4@server4 ~]$ echo $var
|    default
|    [nich4@server4 ~]$

.. note::
    
    变量替换的值也可以使用`(反引号):

    echo ${var:-`pwd`}

* ${var:+default}   # 如果var已经定义, 且为非空时, 则临时使用\”default\”值

|    作用: 测试一个变量是否存在,如果存在,返回default,不存在返回null
|    
|    [nich4@server4 ~]$ unset var
|    [nich4@server4 ~]$ echo ${var:+default}
|    
|    [nich4@server4 ~]$ echo $var
|    
|    [nich4@server4 ~]$ var=old
|    [nich4@server4 ~]$ echo ${var:+default}
|    default
|    [nich4@server4 ~]$ echo $var
|    old
|    [nich4@server4 ~]$ var=\’\’
|    [nich4@server4 ~]$ echo ${var:+default}
|    
|    [nich4@server4 ~]$ echo $var
|    
|    [nich4@server4 ~]$
 
* ${var:?message}       # 判断变量var是否定义,且是否非空
 
|    作用: 捕获未定义变量导致的错误,即如果变量未定义的话,就输出一个错误信息
|    
|    [nich4@server4 ~]$ var=old
|    [nich4@server4 ~]$ echo ${var:?\’Errors!\’}
|    old
|    [nich4@server4 ~]$ var=\’\’
|    [nich4@server4 ~]$ echo ${var:?\’Errors!\’}
|    -bash: var: Errors!
|    [nich4@server4 ~]$ unset var
|    [nich4@server4 ~]$ echo ${var:?\’Errors!\’}
|    -bash: var: Errors!
|    [nich4@server4 ~]$
|    
|    当message没有指定时,shell将显示一条默认的消息:
|    [nich4@server4 ~]$ unset var
|    [nich4@server4 ~]$ echo ${var:?}
|    -bash: var: parameter null or not set
|    [nich4@server4 ~]$ var=\’\’
|    [nich4@server4 ~]$ echo ${var:?}
|    -bash: var: parameter null or not set
|    [nich4@server4 ~]$
 
* ${var:begin:length}       # 截取字符串, 从begin开始截取length长度,不指定length的话就是从begin开始到结尾
 
|    作用: 返回变量值的子串
|    
|    0开始记数, 即begin最小为0, 然后从begin开始截取length个字符
|    
|    [nich4@server4 ~]$ var=\’uplooking.com\’
|    [nich4@server4 ~]$ echo ${var:2:7}
|    looking
|    [root@localhost nich4]#  echo ${var:2}
|    looking.com
|    [nich4@server4 ~]$
 
* ${#var}       # 变量var的值的字符数
 
|    [nich4@server4 ~]$ echo $var
|    uplooking.com
|    [nich4@server4 ~]$ echo ${#var}
|    13
|    [nich4@server4 ~]$
 
* ${var#pattern}    # 去掉变量值开头的与pattern相匹配的部分, 最短匹配模式
* ${var##pattern}   # 同上, 但为最长匹配模式
 
* ${var%pattern}    # 去掉变量值结尾的与pattern相匹配的部分, 最短匹配模式
* ${var%%pattern}   # 同上, 但为最长匹配模式
 
* ${var/pattern/str}    # 用str替换var中的第一个pattern
* ${var//pattern/str}   # 替换var中所有的pattern
 
|    [nich4@server4 ~]$ var=\’/etc/sysconfig/network-scripts/ifcfg-eth0\’
|    [nich4@server4 ~]$ echo ${var#*sc}
|    onfig/network-scripts/ifcfg-eth0
|    [nich4@server4 ~]$ echo ${var##*sc}
|    ripts/ifcfg-eth0
|    
|    [nich4@server4 ~]$ echo $var
|    /etc/sysconfig/network-scripts/ifcfg-eth0
|    [nich4@server4 ~]$ echo ${var%sc*}
|    /etc/sysconfig/network-
|    [nich4@server4 ~]$ echo ${var%%sc*}
|    /etc/sy
|    
|    [nich4@server4 ~]$ echo $var
|    /etc/sysconfig/network-scripts/ifcfg-eth0
|    [nich4@server4 ~]$ echo ${var/sc/XX}
|    /etc/syXXonfig/network-scripts/ifcfg-eth0
|    [nich4@server4 ~]$ echo ${var//sc/XX}
|    /etc/syXXonfig/network-XXripts/ifcfg-eth0
|    [nich4@server4 ~]$ echo ${var//sc/}     # 删除
|    /etc/syonfig/network-ripts/ifcfg-eth0
|    [nich4@server4 ~]$
|    
|    如果模式以#开头,则必须匹配variable的开头
|    如果模式以%开头,则必须匹配var的结尾
|    如果string为null,匹配部分将被删除
|    如果var为@或*,操作被依次应用于每个位置参数并且扩展为结果列表

算术运算
———————————————————————-

* $(( ))

|    [root@localhost nich4]# echo $((4+5))
|    9
|    [root@localhost nich4]# echo $((4-5))
|    -1
|    [root@localhost nich4]# echo $((4*5))
|    20
|    [root@localhost nich4]# echo $((4/5))
|    0
|    [root@localhost nich4]# echo $((4%5))     # 求余
|    4
|    [root@localhost nich4]# echo $((4**5))    # 乘幂
|    1024
|    [root@localhost nich4]#

* $[ ]

|    [root@localhost nich4]# echo $[4+5]
|    9
|    [root@localhost nich4]# echo $[4-5]
|    -1
|    [root@localhost nich4]# echo $[4*5]
|    20
|    [root@localhost nich4]# echo $[4/5]
|    0
|    [root@localhost nich4]# echo $[4%5]
|    4
|    [root@localhost nich4]# echo $[4**5]
|    1024
|    [root@localhost nich4]#

* expr  # 外部命令

|    [root@localhost nich4]# expr 4 + 5
|    9
|    [root@localhost nich4]# expr 4 – 5
|    -1
|    [root@localhost nich4]# expr 4 / 5
|    0
|    [root@localhost nich4]# expr 4 \\* 5
|    20
|    [root@localhost nich4]# expr 4 % 5        
|    4
|    [root@localhost nich4]# expr 4 \\*\\* 5     # 没有乘幂
|    expr: syntax error
|    [root@localhost nich4]# expr 4 ** 5
|    expr: syntax error
|    [root@localhost nich4]#

.. note::

    运算符两边要有空格! \\*号需要转义!

* let

|    [root@localhost nich4]# let var=4+5
|    [root@localhost nich4]# echo $var
|    9
|    [root@localhost nich4]# let var=4*5
|    [root@localhost nich4]# echo $var
|    20
|    [root@localhost nich4]# let var=4%5
|    [root@localhost nich4]# echo $var
|    4
|    [root@localhost nich4]# let var=4-5
|    [root@localhost nich4]# echo $var
|    -1
|    [root@localhost nich4]# let var=4**5
|    [root@localhost nich4]# echo $var
|    1024

* bc

|    [root@localhost nich4]# echo \”4+5\” | bc
|    9
|    [root@localhost nich4]# echo \”4*5\” | bc
|    20
|    [root@localhost nich4]# echo \”4-5\” | bc
|    -1
|    [root@localhost nich4]# echo \”4/5\” | bc
|    0
|    [root@localhost nich4]# echo \”4**5\” | bc
|    (standard_in) 1: parse error
|    [root@localhost nich4]# echo \”4^5\” | bc
|    1024
|    [root@localhost nich4]#

.. note::

    bc是一个功能强大的计算器! 另外, bc只接受标准输入, 非交互下, 除了使用管道, 我们还可以使用\”here string\”(<<<):
    bc <<< 4^5

.. note::

    在脚本中我们经常需要递增(加), 下面的方法都是可以的(参考):

    i=$[i+1]
    $[i++]
    $[++i]

    i=`expr $i + 1`

    i=$(($i+1))

    $((i++))
    ((i++))

    let i=i+1

    let i++

    let $[i++]

    i=`bc<<<$i+1`

    for ((i=0;i<5;i++)) …

 

练习作业:
———————————————————————-

1. 把用户指定目录下的所有空文件删除,最后输出删除的文件个数
    delempty.sh

#. 使用for循环批量添加19个用户,用户名分别是user01~user19,密码为uplooking。添加后批量删除
    addusers.sh   delusers.sh

    01 02 03 …
    1 2 3 …

#. 创建一个/tmp/test目录,里面有3个文件。名字分别为111,222,333。写一个脚本,可以每隔3秒钟循环对这3个文件改名。把111改为222,222改为333,333改为111
    rename.sh

#. 使用for循环测试局域网内(192.168.50.0/24)服务器的网络状态(UP|DOWN)
    ping_serv.sh

#. 提取出/usr/share/doc目录下的所有的文件名为index.html的文件。把他们集中放在/tmp/index目录中。文件名字按提取顺序更名标记。即:第一个找到的index.html命名为index.html.1。第二个为index.html.2。以此类推
    find_index.sh
    
#. 结合所学知识实现下面这个程序:

实现功能菜单:

执行脚本后

按1,显示当前时间

按2,显示剩余内存

按3,显示在线用户

按4,显示CPU负载

按5,退出脚本

按其他字符,提示超出选择范围后退出

::
    
    ————– Menu —————-
    
            1) Show current Time
            2) Memory Free
            3) Online Users
            4) CPU Load
            5) Exit
    
    ————————————
    Enter your choose [1-5]:
   

转载于:Shell/3251865

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » shell的几个重要命令,主要参数,循环语句以及变量处理