linux&shell

Linux经常使用命令

  • 登录时显示信息放在/etc/motd和/etc/profile.d/xxx.sh

    • motd放置字符串
    • profile.d下放置脚本文件
  • echo
    • echo -e 处理特殊字符。若字符串中出现下面字符。则特别加以处理,而不会将它当成一般文字输出:

      • \a 发出警告声;
      • \b 删除前一个字符。
      • \c 最后不加上换行符号;
      • \f 换行但光标仍旧停留在原来的位置。
      • \n 换行且光标移至行首。
      • \r 光标移至行首。但不换行;
      • \t 插入tab;
      • \v 与\f同样;
      • \ 插入\字符;
      • \nnn 插入nnn(八进制)所代表的ASCII字符;
    • echo -n 不换行输出
  • date +%T 以格式化输出当前时间
  • ls -lrt 按时间升序列表显示
  • dirname 路径 dirname $0
  • basename 文件名称
  • 在环境变量文件里使用alias vi=’vim’就可以实现vi取代vim命令

Shell

Shell脚本的建立与运行

Shell 脚本的建立

  • 使用文本编辑器编辑脚本文件

    • vi script-file
  • 为脚本文件加入可运行权限
    • chmod +x script-file

Shell 脚本的运行

  • 在子Shell中运行

    • 变量及结果在结束时从内存销毁,外部shell无法引用
    • bash script-file
    • 或者./script-file
  • 在当前Shell中运行
    • 当前shell可继续引用运行结束shell的变量及结果
    • source script-file
    • . script-file

Shell脚本的编码规范

以 #! 开头:通知系统用何解释器运行此脚本

  • #!/bin/bash
  • 或者#!/bin/sh

以凝视形式说明例如以下的内容:

  • # 脚本名称
  • # 脚本功能
  • # 作者及联系方式
  • # 版本号更新记录
  • # 版权声明
  • # 对算法做简要说明(假设是复杂脚本)
    • 演示样例

      #!/bin/bash
      # This is the first Bash shell program
      # Scriptname: greetings.sh
      echo
      echo -e "Hello $LOGNAME, \c"
      echo    "it‘s nice talking to you."
      echo -n "Your present working directory is: "
      pwd # Show the name of present directory
      echo
      echo -e "The time is `date +%T`!. \nBye"
      echo
      
    • 时间同步shell脚本
      #!/bin/bash
      ## Script Name:/etc/cron.daily/ntpdate
      # 使用NTP的client命令ntpdate与远程NTPserver进行同步
      # 也能够用局域网内的NTPserver替换 pool.ntp.org
      /usr/sbin/ntpdate -s pool.ntp.org
      # 更改硬件时钟时都会记录在/etc/adjtime文件里
      # 使hwclock依据先前的记录来估算硬件时钟的偏差。
      # 并用来校正眼下的硬件时钟
      /sbin/hwclock --adjust
      # 将系统时钟同步到硬件时钟
      /sbin/hwclock –systohc
      

脚本调试方法

在 bash 调用脚本时使用參数

  • bash [-x] [-n] [-v] scriptName

    • sh –x 脚本名

      • 该选项能够使用户跟踪脚本的运行。此时 shell 对脚本中每条命令的处理过程为:先运行替换,然后显示,再运行它。shell 显示脚本中的行时。会在行首加入一个加号 “ + ”
      • 以调试模式运行脚本
    • sh –v 脚本名
      • 在运行脚本之前,按输入的原样打印脚本中的各行
      • 显示脚本中每一个原始命令行及其运行结果
    • sh –n 脚本名
      • 对脚本进行语法检查。但不运行脚本。

        假设存在语法错误,shell 会报错。假设没有错误,则不显示不论什么内容

      • 对脚本进行语法检查

在脚本中使用 bash 内置的 set 命令使整个或部分脚本处于调试模式

  • 开启:set [-x] [-n] [-v]

    • 在脚本内使用set命令开启调试选项

      • set -x :显示由shell运行的命令及其參数
      • set -v :显示由shell读入的命令行
      • set -n :读取命令但不运行他们。用于语法检查
  • 结束:set [+x] [+n] [+v]
    • 在脚本内使用set命令关闭已开启的调试选项

      • set +x
      • set +v
      • set +n
  • 演示样例
        #!/bin/bash
        # This is the first Bash shell program
        # Scriptname: greetings.sh
        set -x ### Turn ON debug mode ###
        echo
        echo -e "Hello $LOGNAME, \c"
        echo    "it‘s nice talking to you."
        echo -n "Your present working directory is: "
        pwd # Show the name of present directory
        echo
        set +x ### Turn OFF debug mode ###
        echo -e "The time is `date +%T`!. \nBye"
        echo
    

Shell脚本的类型

非交互式脚本

  • 不须要读取用户的输入, 也不用向用户反馈某些信息
  • 每次运行都是可预见的, 由于它不读取用户输入, 參数是固定的
  • 能够在后台运行

交互式脚本

  • 脚本能够读取用户的输入, 实时向用户反馈信息(输出某些信息)
  • 这种脚本更灵活, 每次运行时的參数可由用户动态设定
  • 用户界面更友好,但不适用于自己主动化任务(如cron任务)

Shell变量操作

  • 变量替换扩展

    • 变量測试
    • 变量的字符串操作
    • 变量的间接引用
  • 变量的数值计算
    • $[expression]
    • $((expression))
    • expr
    • let
    • declare -i
  • 输入
    • 变量赋值

      • name=value
      • readonly
    • 从标准输入读取
      • read
  • 输出
    • echo
    • printf

变量替换扩展

变量測试

演示样例

字符串计数、截取

演示样例

字符串替换

演示样例

变量的间接引用

  • 通过 str2 的值来引用 str1 的值

    • 错误演示样例

      str1="Hello World"
      str2=str1
      echo $str2
      
    • 正确演示样例
      str1="Hello World"
      str2=str1
      newstr=${!str2}
      echo $newstr
      Hello World
      或
      echo ${!str2}
      Hello World
      或
      eval newstr=\$$str2
      echo $newstr
      Hello World
      或
      eval echo \$$str2
      Hello World
      
  • x=”CENTOS”
  • CENTOS_URL=”http://mirrors.163.com/centos/”
  • 通过 x 的值来引用 CENTOS_URL 的值
    # bash2.0以上才支持
    newstr=${x}_URL
    echo $newstr
    CENTOS_URL
    echo ${!newstr}
    http://mirrors.163.com/centos/
    或
    eval newstr=\$${x}_URL
    echo $newstr
    或
    eval echo \$${x}_URL
    

Shell内置命令——eval

eval arg1 [arg2] … [argN]

* 对參数进行两次扫描和替换

* 将全部的參数连接成一个表达式。并计算或运行该表达式

* 參数中的不论什么变量都将被展开

    listpage="ls -l | more"
    eval $listpage

    eval $(ssh-agent)

    eval newstr=\$$str2
    eval echo \$${x}_URL

Shell 变量的分类

  • 用户自定义变量

    • 由用户自定义、改动和使用
  • Shell 环境变量
    • 由系统维护,用于设置用户的Shell工作环境
    • 仅仅有少数的变量用户能够改动其值
  • 位置參数变量(Positional Parameters)
    • 通过命令行给程序传递运行參数
    • 可用 shift 命令实现位置參数的迁移
  • 专用參数变量(Special Parameters)
    • Bash 提前定义的特殊变量
    • 用户不能改动其值

位置变量

  • 是一组特殊的内置变量

    • 跟在脚本名后面的用空格隔开的每一个字符串
    • 1表示第1个參数值。……,9 表示第9个參数值
    • 10表示第10个參数值,{11} 表示第11个參数值。 ……
  • 位置參数的用途
    • 从 shell 命令/脚本 的命令行接受參数
    • 在调用 shell 函数时为其传递參数

专用參数变量

  • 命令行參数相关

    $*    获取当前shell脚本全部传參的參数,将全部位置參量看成一个字符串(以空格间隔)。相当于""$1$2$3$4$5 。
    [email protected]    将每一个位置參量看成单独的字符串(以空格间隔)"$!" "$2" "...."。
    "$*"  将全部位置參量看成一个字符串(以$IFS间隔)。
    "[email protected]"  将每一个位置參量看成单独的字符串(以空格间隔) 。
    $0    命令行上输入的Shell程序名。
    
    $#    表示命令行上參数的个数。
    
    
  • 进程状态相关
    $?  表示上一条命令运行后的返回值
    $$  当前进程的进程号
    $!  显示运行在后台的最后一个作业的 PID
    $_  在此之前运行的命令或脚本的最后一个參数
    
  • 演示样例

位置參数和 shift 命令

  • shift [n]
  • 将位置參量列表依次左移n次。缺省为左移一次
  • 一旦位置參量列表被移动,最左端的那个參数就会从列表中删除
  • 经常与循环结构语句一起使用,以便遍历每一个位置參数
    #!/bin/sh
    # ScriptName: pp_shift.sh
    # To test Positional Parameters & Shift.
    echo "The script name is :  $0"
    echo ‘$1‘=$1,‘$2‘=$2,‘$3‘=$3,‘$4‘=$4   --   ‘$#‘="$#"
    echo ‘[email protected]‘: "[email protected]"
    shift              # 向左移动全部的位置參数1次
    echo ‘$1‘=$1,‘$2‘=$2,‘$3‘=$3,‘$4‘=$4   --   ‘$#‘="$#"
    echo ‘[email protected]‘: "[email protected]"
    shift 2            # 向左移动全部的位置參数2次
    echo ‘$1‘=$1,‘$2‘=$2,‘$3‘=$3,‘$4‘=$4   --   ‘$#‘="$#"
    echo ‘[email protected]‘: "[email protected]"
    
    $ ./pp_shift.sh  1 b 3 d 4 f
    

退出/返回状态

$?:返回上一条语句或脚本运行的状态

  • 0:成功
  • 1-255:不成功
  • 1:运行正确
  • 126:命令或脚本没有运行权限
  • 127:命令没有找到

exit 命令

  • exit 命令用于退出脚本或当前Shell
  • exit n
    • n 是一个从 0 到 255 的整数
    • 0 表示成功退出,非零表示遇到某种失败
  • 返回值 被保存在状态变量 $? 中

演示样例

    $ echo $$    # 显示当前进程的 PID
    9245
    $ echo $?    # 显示在此之前运行的命令的返回值
    0
    $ bash       # 调用子Shell
    $ echo $$    # 显示当前进程的 PID
    9474
    $ exit 1     # 指定返回值并返回父Shell
    $ echo $?    # 显示上一个Shell/脚本的返回值
    1
    $ list       # 运行不存在的命令
    bash: list: command not found
    $ echo $?
    127
    $ touch bbb.sh
    $ ./bbb.sh   # 运行不具有运行权限的命令
    bash: ./bbb.sh: Permission denied
    $ echo $?

126

read

  • 从键盘输入内容为变量赋值

    • read [-p “信息”] [var1 var2 …]
    • 若省略变量名,则将输入的内容存入REPLY变量
  • 结合不同的引號为变量赋值
    • 双引號 ” ”:同意通过$符号引用其它变量值
    • 单引號 ’ ’:禁止引用其它变量值。$视为普通字符
    • 反撇号 :将命令运行的结果输出给变量

演示样例

    #!/bin/bash
    # This script is to test the usage of read
    # Scriptname: ex4read.sh
    echo "=== examples for testing read ==="
    echo -e "What is your name?

\c"
    read name
    echo "Hello $name"
    echo
    echo -n "Where do you work? "
    read
    echo "I guess $REPLY keeps you busy!"
    echo
    read -p "Enter your job title: "
    echo "I thought you might be an $REPLY."
    echo
    echo "=== End of the script ==="

仅仅读变量

  • 是指不能被清除或又一次赋值的变量
  • readonly variable

演示样例

    [[email protected] ~]$ myname=Osmond
    [[email protected] ~]$ echo $myname
    Osmond
    [[email protected] ~]$ readonly myname
    [[email protected] ~]$ unset myname
    -bash: unset: myname: cannot unset: readonly variable
    [[email protected] ~]$ myname="Osmond Liang"
    -bash: myname: readonly variable

同一时候输出多行信息

  • 使用 echo

  • 使用 here file

整数运算

  • Bash 变量没有严格的类型定义

    • 本质上 Bash 变量都是字符串
  • 若一个字面常量或变量的值是纯数字的。不包括字母或其它字符, Bash能够将其视为长整型值,并可做算数运算和比較运算。
  • Bash 也同意显式地声明整型变量
    • declare -i 变量名

算数运算符

算术运算扩展—在此没有空格的问题

    $ var=test
    $ echo $var
    test
    $ echo $varAA
    $varAA
    $ echo ${var}AA
    testAA

    $ ls
    a b c
    $ echo $(ls)
    a b c
    $ echo `ls`
    a b c

Shell内置命令

let

  • let 内置命令用于算术运算

    num2=1; echo $num2
    let num2=4+1; echo $num2
    let num2=$num2+1; echo $num2
    
  • 赋值符号和运算符两边不能留空格!
  • 假设将字符串赋值给一个整型变量时。则变量的值为 0
  • 假设变量的值是字符串,则进行算术运算时设为 0
    let num2=4 + 1
    let "num2=4 + 1" # 用引號忽略空格的特殊含义
    
  • 用 let 命令进行算术运算时。最好加双引號

expr

  • 通用的表达式计算命令
  • 表达式中參数与操作符必须以空格分开。
  • 表达式中的运算能够是算术运算,比較运算,字符串运算和逻辑运算。
    expr 5 % 3
    expr 5 \* 3        # 乘法符号必须被转义
    expr 2 + 5 \* 2 - 3 % 2
    expr \( 2 + 5 \) \* 2 – 3  # 括号必须被转义
    

浮点数运算

  • bash 仅仅支持整数运算
  • 能够通过使用 bc 或 awk 工具来处理浮点数运算
    n=$(echo "scale=3; 13/2" | bc )
    echo $n
    m=`awk ‘BEGIN{x=2.45;y=3.123;printf "%.3f\n", x*y}‘`
    echo $m
    

printf

  • printf 可用来按指定的格式输出变量
  • printf format 输出參数列表

演示样例

数组变量

  • Bash 2.x 以上支持一维数组,下标从 0 開始
  • 使用 declare 声明或直接给变量名加下标来赋值
    declare -a variable
    variable=(item1 item2 item2 ... )
    
  • 数组的引用
    ${variable[n]}
    

演示样例

declare

  • 内置命令 declare 可用来声明变量
  • declare [选项] variable[=value]

演示样例

    declare myname=osmond
    declare –r myname=osmond
    unset myname
    declare myname=“Osmond Liang"
    declare –x myname2=lrj
    myname2=lrj
    declare –x myname2

变量及相关命令小结


条件測试

  • 条件測试能够推断某个特定条件是否满足

    • 測试之后一般会依据不同的測试值选择运行不同任务
  • 条件測试的种类
    • 命令成功或失败
    • 表达式为真或假
  • 条件測试的值
    • Bash中没有布尔类型变量

      • 退出状态为 0 表示命令成功或表达式为真
      • 非0 则表示命令失败或表达式为假
    • 状态变量 $? 中保存了退出状态的值

演示样例

条件測试语句

  • 语句

    • 格式1: test <測试表达式>
    • 格式2: [ <測试表达式> ]
    • 格式3: [[ <測试表达式> ]] (bash 2.x 版本号以上)
  • 说明
    • 格式1 和 格式2 是等价的,格式3是扩展的 test 命令
    • 在 [[ ]] 中能够使用通配符进行模式匹配
    • &&, ||, <, 和>能够正常存在于[[ ]]中。但不能在 [] 中出现
    • [和[[之后的字符必须为空格,]和]]之前的字符必须为空格
    • 要对整数进行关系运算也能够使用 (()) 进行測试

条件測试操作符

  • 条件測试表达式中可用的操作符

    • 文件測试操作符
    • 字符串測试操作符
    • 整数二元比較操作符
    • 使用逻辑运算符

文件測试

  • 測试:文件是否存在。文件属性,訪问权限等

字符串測试

  • 字符串按从左到右相应字符的ASCII码进行比較

字符串空值检查

检查空值

检查非空值

整数測试

  • 操作符两边必须留空格!

  • 操作符两边的空格可省略

演示样例

逻辑測试

演示样例


流程控制——分支

  • 流程控制语句

    • 分支

      • if 条件语句
      • case 选择语句
    • 循环
      • for 循环语句
      • while 循环语句
      • until 循环语句
      • select 循环与菜单
    • 循环控制
      • break 语句
      • continue 语句
    • 位置參数处理
      • shift 命令
      • getopts 命令

if 语句

    if expr1      # 假设 expr1 为真(返回值为0)
    then          # 那么
       commands1  # 运行语句块 commands1
    elif expr2    # 若 expr1 不真。而 expr2 为真
    then          # 那么
       commands2  # 运行语句块 commands2
     ... ...      # 能够有多个 elif 语句
    else          # else 最多仅仅能有一个
       commands4  # 运行语句块 commands4
    fi            # if 语句必须以单词 fi 终止
  • elif 能够有随意多个(0 个或多个)
  • else 最多仅仅能有一个(0 个或 1 个)
  • if 语句必须以 fi 表示结束
  • exprX 通常为条件測试表达式;也能够是多个命令。以最后一个命令的退出状态为条件值。
  • commands 为可运行语句块,假设为空,需使用 shell 提供的空命令 “ : ”,即冒号。该命令不做不论什么事情,仅仅返回一个退出状态 0
  • if 语句能够嵌套使用

演示样例

case语句

    case expr in # expr 为表达式。关键词 in 不要忘!
      pattern1)  # 若 expr 与 pattern1 匹配。注意括号
       commands1 # 运行语句块 commands1
       ;;        # 跳出 case 结构
      pattern2)  # 若 expr 与 pattern2 匹配
       commands2 # 运行语句块 commands2
       ;;        # 跳出 case 结构
       ... ...    # 能够有随意多个模式匹配
      *)         # 若 expr 与上面的模式都不匹配
       commands  # 运行语句块 commands
       ;;        # 跳出 case 结构
    esac         # case 语句必须以 esac 终止
  • 表达式 expr 按顺序匹配每一个模式,一旦有一个模式匹配成功,则运行该模式后面的全部命令,然后退出 case。
  • 假设 expr 没有找到匹配的模式。则运行缺省值 “ ) ” 后面的命令块 ( 相似于 if 中的 else );“ ) ” 能够不出现。
  • 所给的匹配模式 pattern 中能够含有通配符和“ | ”。

  • 每一个命令块的最后必须有一个双分号。能够独占一行,或放在最后一个命令的后面。


流程控制——循环

    for variable in list
    # 每一次循环。依次把列表 list 中的一个值赋给循环变量
    do          # 循环体開始的标志
      commands  # 循环变量每取一次值,循环体就运行一遍
    done        # 循环结束的标志。返回循环顶部
  • 列表 list 能够是命令替换、变量名替换、字符串和文件名称列表 ( 可包括通配符 )。每一个列表项以空格间隔
  • for 循环运行的次数取决于列表 list 中单词的个数
  • 能够省略 in list 。省略时相当于 in “[email protected]”
  • 首先将 list 的 item1 赋给 variable
    • 运行do和done之间的 commands
  • 然后再将 list 的 item2 赋给 variable
    • 运行do和done之间的 commands

      *如此循环,直到 list 中的全部 item 值都已经用完

演示样例

break 和 continue

  • break [n]

    • 用于强行退出当前循环
    • 假设是嵌套循环。则 break 命令后面能够跟一数字 n。表示退出第 n 重循环(最里面的为第一重循环)
  • continue [n]
    • 用于忽略本次循环的剩余部分。回到循环的顶部,继续下一次循环
    • 假设是嵌套循环,continue 命令后面也可跟一数字 n,表示回到第 n 重循环的顶部

演示样例

for循环(C语言型)语法

    for ((expr1;expr2;expr3)) # 运行 expr1
    do # 若 expr2的值为真时进入循环,否则退出 for循环
      commands  # 运行循环体,之后运行 expr3
    done        # 循环结束的标志,返回循环顶部
  • 通常 expr1和 expr3是算数表达式; expr2是逻辑表达式
  • expr1 仅在循环開始之初运行一次
  • expr2 在每次运行循环体之前运行一次
  • expr3 在每次运行循环体之后运行一次
  • 首先运行 expr1
  • 运行 expr2
    • 其值为假时,终止循环
    • 其值为真时。运行do和done之间的 commands
    • 运行expr3,进入下一次循环

演示样例

while 循环语句

    while expr  # 运行 expr
    do # 若expr的退出状态为0。进入循环,否则退出while
      commands  # 循环体
    done        # 循环结束标志,返回循环顶部

演示样例

* While 和输入重定向

* 使用管道为 while 传递输入

until 循环语句

    until expr  # 运行 expr
    do # 若expr的退出状态非0。进入循环,否则退出until
      commands  # 循环体
    done        # 循环结束标志,返回循环顶部

演示样例

  • 将循环结果通过管道传递给其它命令处理(done |)

  • 后台运行循环(done &)

循环与菜单

  • 一般地。使用 while 循环配合 case实现
  • Bash 提供了专门的 select 循环
    • select 循环主要用于创建菜单
    • select 是个无限循环
      • 通常要配合 case 语句处理不同的选单及退出
      • select 循环的退出
        • 按 ctrl+c 退出循环
        • 在循环体内用 break 命令退出循环
        • 或用 exit 命令终止脚本

演示样例

  • 使用while循环实现菜单

循环结构——select 语法

    select variable in list
    do          # 循环開始的标志
      commands  # 循环变量每取一次值,循环体就运行一遍
    done        # 循环结束的标志
  • 按数值顺序排列的菜单项(list item)会显示到标准输出
  • 菜单项的间隔符由环境变量 IFS 决定
  • 用于引导用户输入的提示信息存放在环境变量 PS3 中
  • 用户输入的值会被存储在内置变量 RELAY 中
  • 用户直接输入回车将又一次显示菜单
  • 与 for 循环相似。省略 in list 时等价于 in “$*”

演示样例


位置參数和命令行參数处理

  • 在脚本中经常使用流程控制处理位置參数

    • 循环结构:while、for
    • 多分支结构:case
  • 在脚本中经常使用例如以下命令配合位置參数处理
    • shift
    • getopts

演示样例

  • 參数位置遍历

  • 位置參数处理举例

选项和參数

  • mybackup -z -c /etc/mybackup.conf -r -v ./foo.txt ./mydir
  • -z是个选项(option)。以减号開始的单字符
  • -c也是个选项,/etc/mybackup.conf 是该选项的附加參数(additional argument )
  • -r和-v也是选项,且不带附加參数
  • ./foo.txt 和 ./mydir 是脚本的处理对象,他们是不与不论什么选项相关的參数,在POSIX?标准中称其为“操作 对象/数”(operands)
  • 依照Linux的命令行书写规范。例如以下命令行
    • mybackup -z -c /etc/mybackup.conf -r -v ./foo.txt ./mydir
  • 也能够写成例如以下的等价形式
    • mybackup -zr -c /etc/mybackup.conf -v ./foo.txt ./mydir
    • mybackup -zv -c /etc/mybackup.conf -r ./foo.txt ./mydir
    • mybackup -vr -c /etc/mybackup.conf -z ./foo.txt ./mydir
    • mybackup -vz -c /etc/mybackup.conf -r ./foo.txt ./mydir
    • mybackup -zrv -c /etc/mybackup.conf ./foo.txt ./mydir

    - mybackup -zrvc /etc/mybackup.conf ./foo.txt ./mydir

  • 用户使用自己的代码分析这些选项将变得十分困难
  • Shell的内置命令getopts能够识别全部常见的选项格式,为用户处理选项和參数提供了方便

内置命令——getopts

  • getopts OPTSTRING VARNAME [ARGS…]
  • OPTSTRING
    • 是由若干有效的选项标识符组成的选项字符串
    • 若某选项标识符后有冒号,则表示此选项有附加參数
    • 若整个字符串前有冒号,将使用“安静”的错误模式
  • VARNAME :每次匹配成功的选项保存在变量中
  • ARGS : 參数列表。省略时为 ”[email protected]”
  • getopts c:zrv opt
  • getopts :c:zrv opt
  • getopts的运行过程
    • 通常须要以循环的方式运行多次 getopts 来解析位置參数中的选项以及可能存在的选项附加參数

      *每次调用 getopts,将会处理參数列表中的“下一个”选项

      • 将选项存储在VARNAME变量中
      • 将此选项相应的附加參数存储在环境变量OPTARG中
      • 对环境变量OPTIND进行自增操作,使 $OPTIND 总是指向原始參数列表中“下一个”要处理的元素位置
      • 若VARNAME与OPTSTRING的全部选项均不匹配,则做“invalid option”的错误设置
      • 若某选项的參数不存在。则做“required argument not found”的错误设置
  • getopts的错误报告模式
  • 冗余(Verbose)模式( OPTSTRING 不以:开头)
    • “invalid option”

      • VARNAME=“?” ; unset OPTARG
    • “required argument not found”
      • VARNAME=“?” ; unset OPTARG 并输出错误信息
  • 安静(Silent)模式( OPTSTRING 以:开头)
    • “invalid option”

      • VARNAME=“?” ; OPTARG=‘无效的选项字符’
    • “required argument not found”
      • VARNAME=“:” ; OPTARG=‘与參数相应的选项字符’

while循环与getopts处理

    while getopts  OPTSTRING  VARNAME
    do
      case $VARNAME in
        …) ………… ;;
        …) ………… ;;
        :) ………… ;;
       \?) ………… ;;
      esac
    done
  • getopts 返回假时终止 while 循环

    • 当 getopts 遭遇到第一个非选项參数时终止解析
    • 当 getopts 遭遇到 “–”參数时终止解析

getopts的注意事项

  • getopts 不能解析 GNU-style 长參数 (–myoption)
  • getopts从不改变原始位置參数
    • 若希望移动位置參数,需手工运行 shift
  • getopts会自己主动对变量 OPTIND 做自增处理
    • OPTIDX的初始值为 1
    • 若要又一次解析命令行參数,需将OPTIDX的值置为 1
  • getopts 遭遇到第一个非选项參数时终止解析
    • 终止解析后运行命令

      • shift ((OPTIND-1))
    • 能够使 ”[email protected]” 仅仅包括“操作 对象/数”(operands

演示样例

  • 演示样例1

    #!/bin/bash
    ## filename : pp_parse_getopts_1.sh
    while getopts  "abc:def:ghi" flag
    do
      echo "$flag" $OPTIND $OPTARG
    done
    echo "Resetting"
    OPTIND=1
    while getopts  "bc:def:ghi" flag
    do
      echo "$flag" $OPTIND $OPTARG
    done
    
    $ ./pp_parse_getopts_1.sh -a -bc foo -f "foo bar" -h –gde
    $ ./pp_parse_getopts_1.sh -abf "foo bar" -h -gde –c
    $ ./pp_parse_getopts_1.sh -abf “foo bar” -h –c -gde
    
  • 演示样例2
    #!/bin/bash
    ## filename : pp_parse_getopts_2.sh
    while getopts  ":abc:def:ghi" flag
    do
      echo "$flag" $OPTIND $OPTARG
    done
    echo "Resetting"
    OPTIND=1
    while getopts  ":bc:def:ghi" flag
    do
      echo "$flag" $OPTIND $OPTARG
    done
    
    $ ./pp_parse_getopts_2.sh -a -bc foo -f "foo bar" -h -gde
    $ ./pp_parse_getopts_2.sh -abf "foo bar" -h -gde –c
    $ ./pp_parse_getopts_1.sh -abf “foo bar” -h –c -gde
    

* 演示样例3

    #!/bin/bash
    ## filename : mybackup_getopts.sh
    while getopts :zc:x:rv opt
    do
      case $opt in
        c) ConfFile=$OPTARG       ;;
        x) ExcludeFile=$OPTARG    ;;
        z) Compress=true          ;;
        r) Recursive=true         ;;
        v) Verbose=true           ;;
        :)
          echo "$0: Must supply an argument to -$OPTARG." >&2
          exit 1
          ;;
        \?) echo "Invalid option -$OPTARG ignored." >&2   ;;
      esac
    done

    shift $((OPTIND-1)) ; echo $0 ; echo "[email protected]"
  • 演示样例4

    #!/bin/bash
    ## filename : mybackup_getopts2.sh
    while getopts :zc:x:rv opt
    do
      case $opt in
        c) if [[ $OPTARG = -* ]]; then  ((OPTIND--)) ;  continue ;  fi
           ConfFile=$OPTARG       ;;
        x) ExcludeFile=$OPTARG    ;;
        z) Compress=true          ;;
        r) Recursive=true         ;;
        v) Verbose=true           ;;
        :)
          echo "$0: Must supply an argument to -$OPTARG." >&2
          exit 1
          ;;
        \?) echo "Invalid option -$OPTARG ignored." >&2   ;;
      esac
    done
    
    shift ((OPTIND-1)) ; echo $0 ; echo "[email protected]"
    

函数

  • 为了避免大型脚本变得复杂、晦涩而使用函数
  • 将大型脚本代码切割成小块。将这些被命名的代码块称为函数
    • 一个函数就是一个子程序。用于完毕特定的任务

      • 如:加入一个用户、推断用户是否为管理员 等
  • 函数定义之后能够被使用它的主程序调用
    • 调用函数的方法与运行Shell命令无异
    • 能够在Shell脚本中调用(函数需先定义而后调用)
    • 在命令行上直接调用(定义函数的文件需先载入

合理使用Shell函数

  • 简化程序代码,实现代码重用

    • 实现一次定义多次调用。如:is_root_user()函数能够由不同的shell脚本反复使用。
  • 实现结构化编程
    • 使脚本内容更加简洁。增强程序的易读性
  • 提高运行效率
    • 将经常使用的功能定义为多个函数并将其保存在一个文件里

      • 相似其它语言的“模块”文件
    • 在 ~/bashrc 或命令行上使用 source 命令调用这个文件
    • 此文件里定义的多个函数一次性地调入内存,从而加快运行速度

函数的定义和调用

函数定义

函数调用

  • 仅仅需输入函数名就可以调用函数

    • 函数名
    • 函数名 參数1 參数2 …
  • 函数必须在调用之前定义

函数的存储和显示

  • 函数的存储

    • 函数和调用它的主程序保存在同一个文件里

      *函数的定义必须出如今调用之前

      *函数和调用它的主程序保存在不同的文件里

      • 保存函数的文件必须先使用 source 命令运行,之后才干调用当中的函数
  • 函数的显示
    • 显示当前Shell可见的全部函数名

      • $ declare -F
    • 显示当前Shell可见的全部(指定)的函数定义
      • $ declare -f
      • $ declare -f

演示样例

  • 函数的定义和调用

    • 演示样例1

      #!/bin/bash
      ## filename: all_in_one_backup_select.sh
      ### User define Function (UDF) ###
      sql_bak  () { echo "Running mysqldump tool..."; }
      sync_bak () { echo "Running rsync tool..."; }
      git_bak  () { echo "Running gistore tool..."; }
      tar_bak  () { echo "Running tar tool..."; }
      ### Main script starts here ###
      PS3="Please choose a backup tools : "
      select s in  mysqldump rsync gistore tar quit ; do
        case $REPLY in
             1) sql_bak  ;;
             2) sync_bak ;;
             3) git_bak  ;;
             4) tar_bak  ;;
             5) exit     ;;
        esac
      done
      
    • 演示样例2
      #!/bin/bash
      ## filename: /root/bin/my_backup_functions.sh
      ### User define Function (UDF) ###
      sql_bak  () { echo "Running mysqldump tool..."; }
      sync_bak () { echo "Running rsync tool..."; }
      git_bak  () { echo "Running gistore tool..."; }
      tar_bak  () { echo "Running tar tool..."; }
      
    • 演示样例3
      #!/bin/bash
      ## filename: all_in_one_backup_select.sourcefunc.sh
      source /root/bin/my_backup_functions.sh
      ### Main script starts here ###
      PS3="Please choose a backup tools : "
      select s in  mysqldump rsync gistore tar quit ; do
        case $REPLY in
             1|[mM]ysqldump) sql_bak  ;;
             2|[rR]sync)     sync_bak ;;
             3|[gG]istore)   git_bak  ;;
             4|[tT]ar)       tar_bak  ;;
             5) exit     ;;
        esac
      done
      

函数与变量

  • 參数(Arguments)

    • 调用函数时。使用位置參数的形式为函数传递參数
    • 函数内的1?{n} 、?和@ 表示其接收的參数
    • 函数调用结束后位置參数 1?{n} 、?和@ 将被重置为调用函数之前的值
    • 在主程序和函数中,$0始终代表脚本名
  • 变量(Variables)

    *函数内使用 local 声明的变量是局部(Local)变量

    *局部变量的作用域是当前函数以及其调用的全部函数

    • 函数内未使用 local 声明的变量是全局(Global)变量

      *即主程序和函数中的同名变量是一个变量(地址一致

演示样例

  • 函数与位置參数

    • 演示样例1

      #!/bin/bash
      ## filename: pp_and_function.sh
      echo "===Print positional parameters in main :"
      echo "$0: $*"
      pp1(){
        echo ‘f1--Print $* parameters in fun1 :‘ ; echo "$0: $*"
      }
      pp2(){
        echo ‘f2--Print $* parameters in fun1 :‘ ; echo "$0: $*"
        pp1 1st 2nd 3th 4th 5th 6th 7th 8th 9th
        echo ‘f2--Print $* parameters in fun1 :‘ ; echo "$0: $*"
      }
      pp1 1 2 3 4 5 6 7 8 9
      echo "===Print positional parameters in main :"
      echo "$0: $*"
      pp2 I II III IV V VI VII VIII IX
      
      ./pp_and_function.sh  a b c d e f g h i
      
    • 演示样例2
      #!/bin/bash
      ## filename: function_max.sh
      # User define Function (UDF)
      usage () {
        echo "List the MAX of the positive integers in command line. "
        echo "Usage: `basename $0` <num1> <num2> [ <num3> ... ]"
        exit
      }
      max () {
        [[ -z $1 || -z $2 ]] && usage
        largest=0
        for i ; do  ((i>largest)) && largest=$i ; done
      }
      ### Main script starts here ###
      max "[email protected]"
      echo "The largest of the numbers is $largest."
      
      ./function_max.sh  1 58 111 32768 66
      
  • 由于largest变量在函数max内没有使用local声明,所以它是全局的

函数的结束与返回值

  • 当函数的最后一条命令运行结束函数即结束

    • 函数的返回值就是最后一条命令的退出码
    • 其返回值被保存在系统变量$?中
  • 能够使用 return 或 exit 显式地结束函数
    • return [N]

      • return 将结束函数的运行
      • 能够使用 N 指定函数返回值
    • exit [N]
      • exit 将中断当前函数及当前Shell的运行
      • 能够使用 N 指定返回值

演示样例

    #!/bin/bash
    ## filename: function_max2.sh
    # User define Function (UDF)
    max2 () {
      if [[ -z $1 || -z $2 ]] ; then
        echo  "Need 2 parameters to the function." ; exit
      fi
      [ $1 -eq $2 ] &&
           { echo "The two numbers are equal." ; exit ; }
      (($1>$2)) && return $1 || return $2
    }
    ### Main script starts here ###
    read -p "Please input two integer numbers  : " n1 n2
    echo "n1=$n1 , n2=$n2“
    max2 $n1 $n2
    return_val=$?
    echo "The larger of the two numbers is $return_val."

函数返回值

  • 使用全局变量引用函数的值不利于结构化编程
  • 使用 return 或 exit 仅仅能返回整数值
  • 使用标准输出实现函数的返回值
    • 是一种通用的方法。既能返回整数又能返回字符串
    • 函数结束前使用 echo 命令将结果显示到标准输出
    • 调用函数时使用例如以下的格式将函数的输出结果存到变量 RES 中,之后便可使用变量 $RES 的值(或输出、或运行測试、或进一步处理等)
    • RES=$(functionName)
    • echo $RES

演示样例

  • 使用标准输出返回函数值

    #!/bin/bash
    ## filename: function_to-upper.sh
    # User define Function (UDF)
    to_upper () {
        local str="[email protected]"
        local output
        output=$(tr ‘[a-z]‘ ‘[A-Z]‘<<<"${str}")
        echo $output
    }
    ### Main script starts here ###
    to_upper "This Is a TEST"
    
    res=$(to_upper "[email protected]")
    echo "$res"
    
    res=$(to_upper "$1")
    [[ $res == "YES" ]] && echo "Continue..." || echo "Stop"
    
    ./function_to-upper.sh YES we are
    ./function_to-upper.sh No we are not
    
  • 系统INIT 启动脚本的结构——/etc/rc.d/init.d/*

时间: 2024-11-09 21:11:46

linux&amp;shell的相关文章

linux下shell脚本执行方法及exec和source命令

exec和source都属于bash内部命令(builtins commands),在bash下输入man exec或man source可以查看所有的内部命令信息. bash shell的命令分为两类:外部命令和内部命令.外部命令是通过系统调用或独立的程序实现的,如sed.awk等等.内部命令是由特殊的文件格式(.def)所实现,如cd.history.exec等等. 在说明exe和source的区别之前,先说明一下fork的概念. fork是linux的系统调用,用来创建子进程(child

Linux系统shell脚本编程——生产实战案例

Linux系统shell脚本编程--生产实战案例     在日常的生产环境中,可能会遇到需要批量检查内网目前在线的主机IP地址有哪些,还可能需要检查这些在线的主机哪些端口是开放状态,因此依靠手工来检查是可以实现,但比较费时费力,所以需要结合shell脚本来实现批量检查的功能,那么今天就来做个小小的实验. 1.开发脚本前准备 一般大家都知道,测试主机是否在线,常用的命令无非就是ping.nmap,因此,首先找一个地址来测试下ping命令的效果 [[email protected] scripts]

Linux/Unix shell sql 之间传递变量

灵活结合Linux/Unix Shell 与SQL 之间的变量传输,极大程度的提高了DBA的工作效率,本文针对Linux/Unix shell sql 之间传递变量给出几个简单的示例以供参考. Linux/Unix 下调用SQL,RAMN 请参考:Linux/Unix shell 脚本中调用SQL,RMAN脚本 一.示例 [python] view plain copy print? 1.shell变量接受sql返回值之方式一 [email protected]:~> more ./retval

Linux/Unix shell 监控Oracle告警日志(monitor alter log file)

使用shell脚本实现对Oracle数据库的监控与管理将大大简化DBA的工作负担,如常见的对实例的监控,监听的监控,告警日志的监控,以及数据库的备份,AWR report的自动邮件等.本文给出Linux 下使用 shell 脚本来监控 Oracle 告警日志(monitor alter log file). Linux Shell的相关参考:        Linux/Unix shell 脚本中调用SQL,RMAN脚本        Linux/Unix shell sql 之间传递变量   

Linux学习 -- Shell基础 -- 概述

Shell是什么? 命令解释器 编程语言 Linux支持的Shell类型 cat /etc/shells 主要学习 bash 脚本执行方式 echo echo -e 单引号 -- 原始字符串  双引号 -- 支持转义字符串 \e[1;31m xxx  开启颜色 \e[0m    关闭颜色 首行:#!/bin/bash #写好注释 执行方式: 方式1 sh xxx.sh 方式2 chmod 755 xxx.sh  ./xxx.sh 或 绝对路径 Linux学习 -- Shell基础 -- 概述

Linux修改Shell命令提示符及颜色

Linux修改Shell命令提示符及颜色 1. Linux登录过程中加载配置文件顺序: /etc/profile → /etc/profile.d/*.sh → ~/.bash_profile → ~/.bashrc → [/etc/bashrc] 可查看默认的~/.bashrc文件如下: [root@~/wade/codeReview/redis-2.8.17] cat ~/.bashrc # .bashrc   # User specific aliases and functions  

Linux的shell终端常用快捷键大全

在日常工作中,许多事情要经常与电脑打交道,特别是高频率地使用一些专业性的软件,或者是玩一些键盘流性质的游戏,就应该熟知常用的快捷键,这样玩起来不仅高效,而且略显专业性. 对于某些IT工作者来说,Linux的shell终端是一个经常要用到的工具,如果能够熟练使用快捷键,做起事情来且不事半功倍. 下面列举一些shell终端常用的快捷键,它们一般是Shift.Ctrl.Alt键与其它按键的组合键,这些快捷键都在Ubuntu/GNOME上做过测试,可以正常使用. 1. 设置快捷键 快捷键设置可以打开sh

Linux使用shell自动切换网关

编写名为auto_change_gw.sh的脚本,用来自动切换主机网关,相关说明如下: 1)有2个可用的网关地址,分别是主网关192.168.10.254和备用网关192.168.10.253,当前使用的默认网关是192.168.10.254: 2)若当前使用的网关地址192.168.10.254出现问题,自动把网关地址切换为192.168.10.253: 3)当网关地址192.168.10.254能正常工作后,当前主机再把网关地址切换到192.168.10.254. 讲下思路: 1.先用whi

linux下的shell命令的编写,以及java如何调用linux的shell命令(java如何获取linux上的网卡的ip信息)

程序员都很懒,你懂的! 最近在开发中,需要用到服务器的ip和mac信息.但是服务器是架设在linux系统上的,对于多网口,在获取ip时就产生了很大的问题.下面是在windows系统上,java获取本地ip的方法.贴代码: package com.herman.test; import java.net.InetAddress; /** * @see 获取计算机ip * @author Herman.Xiong * @date 2014年5月16日 09:35:38 */ public class

Linux/Unix shell 监控Oracle监听器(monitor listener)

使用shell脚本实现对Oracle数据库的监控与管理将大大简化DBA的工作负担,如常见的对实例的监控,监听的监控,告警日志的监控,以及数据库的备份,AWR report的自动邮件等.本文给出Linux 下使用 shell 脚本来监控 Oracle 监听器. Linux Shell的相关参考:        Linux/Unix shell 脚本中调用SQL,RMAN脚本        Linux/Unix shell sql 之间传递变量        Linux/Unix shell 调用