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 。
    $@ 将每一个位置參量看成单独的字符串(以空格间隔)"$!" "$2" "...."。
    "$*" 将全部位置參量看成一个字符串(以$IFS间隔)。
    "$@" 将每一个位置參量看成单独的字符串(以空格间隔) 。
    $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 '$@': "$@"
    shift # 向左移动全部的位置參数1次
    echo '$1'=$1,'$2'=$2,'$3'=$3,'$4'=$4 -- '$#'="$#"
    echo '$@': "$@"
    shift 2 # 向左移动全部的位置參数2次
    echo '$1'=$1,'$2'=$2,'$3'=$3,'$4'=$4 -- '$#'="$#"
    echo '$@': "$@" $ ./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

演示样例

    [lrj@centos1 ~]$ myname=Osmond
[lrj@centos1 ~]$ echo $myname
Osmond
[lrj@centos1 ~]$ readonly myname
[lrj@centos1 ~]$ unset myname
-bash: unset: myname: cannot unset: readonly variable
[lrj@centos1 ~]$ 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 “$@”

  • 首先将 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 : 參数列表。省略时为 ”$@”

  • 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))
    • 能够使 ”$@” 仅仅包括“操作 对象/数”(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 "$@"
  • 演示样例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 "$@"

函数

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

      • 如:加入一个用户、推断用户是否为管理员 等
  • 函数定义之后能够被使用它的主程序调用
    • 调用函数的方法与运行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 "$@"
      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="$@"
    local output
    output=$(tr '[a-z]' '[A-Z]'<<<"${str}")
    echo $output
    }
    ### Main script starts here ###
    to_upper "This Is a TEST" res=$(to_upper "$@")
    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/*

linux&amp;shell的更多相关文章

  1. 详解Linux交互式shell脚本中创建对话框实例教程_linux服务器

    本教程我们通过实现来讲讲Linux交互式shell脚本中创建各种各样对话框,对话框在Linux中可以友好的提示操作者,感兴趣的朋友可以参考学习一下. 当你在终端环境下安装新的软件时,你可以经常看到信息 ...

  2. linux中shell变量$#,$@,$0,$1,$2的含义解释

    linux中shell变量$#,$@,$0,$1,$2的含义解释: 变量说明: $$ Shell本身的PID(ProcessID) $! Shell最后运行的后台Process的PID $? 最后运行 ...

  3. 使用C#给Linux写Shell脚本(下篇)

    在上篇的<使用C#给Linux写Shell脚本>结尾中,我们留下了一个关于C#如何调用BashShell的问题.在文章发布之后,我留意到有读者留言推荐使用“Pash”(一款类PowerSh ...

  4. linux中用shell获取昨天、明天或多天前的日期

    linux中用shell获取昨天.明天或多天前的日期 时间 -- :: BlogJava-专家区 原文 http://www.blogjava.net/xzclog/archive/2015/12/0 ...

  5. linux中用shell获取时间,日期

    linux中用shell获取昨天.明天或多天前的日期:在Linux中对man date -d 参数说的比较模糊,以下举例进一步说明:# -d, --date=STRING display time d ...

  6. Linux 的shell 字符串截取很有用。有八种方法。

    一 Linux 的字符串截取很有用.有八种方法. 假设有变量 var=http://www.linuxidc.com/123.htm 1  # 号截取,删除左边字符,保留右边字符. echo ${va ...

  7. Linux Bash Shell 快速入门

    BASH 的基本语法 最简单的例子 —— Hello World! 关于输入.输出和错误输出 BASH 中对变量的规定(与 C 语言的异同) BASH 中的基本流程控制语法 函数的使用 2.1     ...

  8. linux,shell输入反斜杠显示'W'。

    linux,shell输入反斜杠显示'W'. solution: 字体必须为"Courier New".

  9. 06 Linux下Shell介绍

    一.概述 每个人在成功登陆Linux后,系统会出现不同的提示符号,例如$,~,#等,然后你就可以开始输入需要的命令.若命令正确,系统就会依据命令的要求来执行,直到注销系统为止,在登陆到注销期间,输入的 ...

  10. linux BASH shell设置字体与背景颜色

    linux BASH shell下设置字体及背景颜色的方法. BASH shell下设置字体及背景颜色  echo -e "\e[31mtest\e[41m"  \e[30m 将字 ...

随机推荐

  1. 【BZOJ 2510】 2510: 弱题 (矩阵乘法、循环矩阵的矩阵乘法)

    2510: 弱题 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 374  Solved: 196 Description 有M个球,一开始每个球均有一 ...

  2. luoguP3239 [HNOI2015]亚瑟王 概率期望DP

    当初怎么想的来着.....又忘了...... 首先,总期望 = 每张卡片的期望之和 求期望,只要我们求出每张卡片被用掉的概率即可 如果直接上状态$f[i][j]$表示在第$i$轮中,第$j$张牌发动的 ...

  3. POJ2222 Keywords Search AC自动机模板

    http://acm.hdu.edu.cn/showproblem.php?pid=2222 题意:给出一些单词,求多少个单词在字符串中出现过(单词表单词可能有相同的,这些相同的单词视为不同的分别计数 ...

  4. [转载]C++内存管理

    [导语] 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不 ...

  5. bzoj1375 双调路径

    Description 来越多,因此选择最佳路径是很现实的问题.城市的道路是双向的,每条道路有固定的旅行时间以及需要支付的费用.路径由连续的道路组成.总时间是各条道路旅行时间的和,总费用是各条道路所支 ...

  6. 【原】配置Log4j,使得MyBatis打印出SQL语句

    [环境参数] JDK:jdk1.8.0_25 IDE:Eclipse Luna Servie Release 1 框架:Spring 4.1.5 + SpringMVC 4.1.5 + MyBatis ...

  7. POJ 3525 Most Distant Point from the Sea (半平面交+二分)

    Most Distant Point from the Sea Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 3476   ...

  8. GNU make 指南

    http://docs.huihoo.com/gnu/linux/gmake.html GNU make 指南 翻译: 哈少 译者按: 本文是一篇介绍 GNU Make 的文章,读完后读者应该基本掌握 ...

  9. STM32F401

    The STM32F401 line is the entry level to the STM32 F4 series. It is designed for medical, industrial ...

  10. Druid如何自动根据URL自动识别DriverClass的

    Druid是根据url前缀来识别DriverClass的,这样使得配置更方便简洁. 前缀 DriverCLass 描述信息 jdbc:odps com.aliyun.odps.jdbc.OdpsDri ...