精华内容
下载资源
问答
  • sh(bash) 参数索引查找

    2019-06-03 18:28:11
    1,变量说明 $$ Shell本身的PID(ProcessID) ...如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。 $@ 所有参数列表。如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出...

    1,变量说明
    $$
    Shell本身的PID(ProcessID)
    $!
    Shell最后运行的后台Process的PID
    $?
    最后运行的命令的结束代码(返回值)
    $-
    使用Set命令设定的Flag一览
    $*
    所有参数列表。如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
    $@
    所有参数列表。如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
    $#
    添加到Shell的参数个数
    $0
    Shell本身的文件名
    $1~$n
    添加到Shell的各参数值。$1是第1参数、$2是第2参数…。

    2,查找关键参数的方法

    #!/bin/bash
    for argv in $*
    do
    echo "argv:$argv"
     fi
    done

    #!/bin/bash

    while [ $# != 0 ];do

    echo "第一个参数为:$1,参数个数为:$#"

    shift

    done

    while [ "$#" != 0 ]; do
    [ "x$1" = "xON" ] && IN_ONOFF=on
    [ "x$1" = "xOFF" ] && IN_ONOFF=off
    shift
    done

    shift(shift 1) 命令每执行一次,变量的个数($#)减一(之前的$1变量被销毁,之后的$2就变成了$1),而变量值提前一位

    for i in $(seq 1 $#)do#通过eval把i变量的值($i)作为变量j的名字eval j=$$iecho "第$i个参数($"$i"):$j"done
    

     

     

    展开全文
  • Bash 参数参数扩展

    2019-06-17 15:19:11
    Bash 参数参数扩展 在脚本中传递和分析参数 文档选项 打印本页 将此页作为电子邮件发送 讨论 级别: 中级 Ian Shields, 高级...

    Bash 参数和参数扩展

    在脚本中传递和分析参数

    developerWorks
    文档选项
    将打印机的版面设置成横向打印模式

    打印本页

    将此页作为电子邮件发送

    将此页作为电子邮件发送

    讨论


    级别: 中级

    Ian Shields, 高级程序员, IBM 

    2007 年 7 月 30 日

    您是否有时想知道如何对脚本使用参数,以及如何将参数传递给内部函数或其他脚本?是否需要对参数或选项做一些简单的有效性测试?或者对参数字符串执行一些简单的析取和替换操作?本文将向您介绍参数的用法和 bash shell 中的各种参数扩展。

    现在,很多 Linux® 和 UNIX® 系统上都有 bash shell,它是 Linux 上常见的默认 shell。通过本文,您将了解到如何在 bash 脚本中处理参数和选项,以及如何使用 shell 的参数扩展检查或修改参数。本文重点介绍 bash,文中的示例都是在以 bash 为 shell 的 Linux 系统上运行。但是,很多其他的 shell 中也有这些扩展,比如 ksh、ash 或 dash,您可以在其他 UNIX 系统或者甚至是 Cygwin 之类的环境中使用这些 shell 和扩展。早前的一篇文章 Linux 技巧:Bash 测试和比较函数 已经对本文中的构建工具进行了介绍。本文中的某些材料摘录自 developerWorks 教程 LPI 102 考试准备,主题 109: Shell、脚本、编程和编译,该教程介绍了很多基本的脚本编程技术。

    传递的参数

    函数和 shell 脚本的妙处之一是,通过向单个函数或脚本传递参数 能够使它们表现出不同的行为。在本节中,您将了解到如何识别和使用传递的参数。

    在函数或脚本中,您可以使用表 1 中列出的 bash 特殊变量来引用参数。您可以给这些变量附上 $ 符号的前缀,然后像引用其他 shell 变量那样引用它们。

    表 1. 函数的 Shell 参数
    参数目的
    0, 1, 2, ...位置参数从参数 0 开始。参数 0 引用启动 bash 的程序的名称,如果函数在 shell 脚本中运行,则引用 shell 脚本的名称。有关该参数的其他信息,比如 bash 由 -c 参数启动,请参阅 bash 手册页面。由单引号或双引号包围的字符串被作为一个参数进行传递,传递时会去掉引号。如果是双引号,则在调用函数之前将对 $HOME 之类的 shell 变量进行扩展。对于包含嵌入空白或其他字符(这些空白或字符可能对 shell 有特殊意义)的参数,需要使用单引号或双引号进行传递。
    *位置参数从参数 1 开始。如果在双引号中进行扩展,则扩展就是一个词,由 IFS 特殊变量的第一个字符将参数分开,如果 IFS 为空,则没有间隔空格。IFS 的默认值是空白、制表符和换行符。如果没有设置 IFS,则使用空白作为分隔符(仅对默认 IFS 而言)。
    @位置参数从参数 1 开始。如果在双引号中进行扩展,则每个参数都会成为一个词,因此 “$@” 与 “$1” “$2” 等效。如果参数有可能包含嵌入空白,那么您将需要使用这种形式。
    #参数数量(不包含参数 0)。

    注意:如果您拥有的参数多于 9 个,则不能使用 $10 来引用第十个参数。首先,您必须处理或保存第一个参数($1),然后使用 shift 命令删除参数 1 并将所有剩余的参数下移一位,因此 $10 就变成了 $9,依此类推。$# 的值将被更新以反映参数的剩余数量。在实践中,最常见的情况是将参数迭代到函数或 shell 脚本,或者迭代到命令替换使用 for 语句创建的列表,因此这个约束基本不成问题。

    现在,您可以定义一个简单函数,其用途只是告诉您它所拥有的参数数量并显示这些参数,如清单 1 所示。


    清单 1. 函数参数
                    
    [ian@pinguino ~]$ testfunc () { echo "$# parameters"; echo "$@"; }
    [ian@pinguino ~]$ testfunc
    0 parameters
    
    [ian@pinguino ~]$ testfunc a b c
    3 parameters
    a b c
    [ian@pinguino ~]$ testfunc a "b c"
    2 parameters
    a b c
    

    Shell 脚本处理参数的方式与函数处理参数的方式相同。实际上,您会经常发现,脚本往往由很多小型的函数装配而成。清单 2 给出了一个 shell 脚本 testfunc.sh,用于完成相同的简单任务,结果是要使用上面的一个输入来运行这个脚本。记住使用 chmod +x 将脚本标记为可执行。


    清单 2. Shell 脚本参数
                    
    [ian@pinguino ~]$ cat testfunc.sh
    #!/bin/bash
    echo "$# parameters"
    echo "$@";
    [ian@pinguino ~]$ ./testfunc.sh a "b c"
    2 parameters
    a b c
    

    在表 1 中您会发现,shell 可能将传递参数的列表引用为 $* 或 $@,而是否将这些表达式用引号引用将影响它们的解释方式。对于上面的函数而言,使用 $*、“$*”、$@ 或 “$@” 输出的结果差别不大,但是如果函数更复杂一些,就没有那么肯定了,当您希望分析参数或将一些参数传递给其他函数或脚本时,使用或不用引号的差别就很明显。清单 3 给出了一个函数,用于打印参数的数量然后根据这四种可选方案打印参数。清单 4 给出了使用中的函数。IFS 默认变量使用一个空格作为它的第一个字符,因此清单 4 添加了一条竖线作为 IFS 变量的第一个字符,更加清楚地显示了在 “$*” 扩展中的何处使用这个字符。


    清单 3. 一个探究参数处理差别的函数
                    
    [ian@pinguino ~]$ type testfunc2
    testfunc2 is a function
    testfunc2 ()
    {
        echo "$# parameters";
        echo Using '$*';
        for p in $*;
        do
            echo "[$p]";
        done;
        echo Using '"$*"';
        for p in "$*";
        do
            echo "[$p]";
        done;
        echo Using '$@';
        for p in $@;
        do
            echo "[$p]";
        done;
        echo Using '"$@"';
        for p in "$@";
        do
            echo "[$p]";
        done
    }
    


    清单 4. 使用 testfunc2 打印参数信息
                    
    [ian@pinguino ~]$ IFS="|${IFS}" testfunc2 abc "a bc" "1 2
    > 3"
    3 parameters
    Using $*
    [abc]
    [a]
    [bc]
    [1]
    [2]
    [3]
    Using "$*"
    [abc|a bc|1 2
    3]
    Using $@
    [abc]
    [a]
    [bc]
    [1]
    [2]
    [3]
    Using "$@"
    [abc]
    [a bc]
    [1 2
    3]
    

    仔细研究二者的差别,尤其要注意加引号的形式和包含空白(如空格字符和换行符)的参数。在一个 [] 字符对中,注意:“$*” 扩展实际上是一个词。





    回页首


    选项和 getopts

    传统的 UNIX 和 Linux 命令将一些传递的参数看作选项。过去,这些参数是单个的字符开关,与其他参数的区别在于拥有一个前导的连字符或负号。为方便起见,若干个选项可以合并到 ls -lrt 命令中,它提供了一个按修改时间(-t 选项)反向(-r 选项)排序的长(-l 选项)目录清单。

    您可以对 shell 脚本使用同样的技术,getopts 内置命令可以简化您的任务。要查看此命令的工作原理,可以考虑清单 5 所示的示例脚本 testopt.sh。


    清单 5. testopt.sh 脚本
                    
    #!/bin/bash
    echo "OPTIND starts at $OPTIND"
    while getopts ":pq:" optname
      do
        case "$optname" in
          "p")
            echo "Option $optname is specified"
            ;;
          "q")
            echo "Option $optname has value $OPTARG"
            ;;
          "?")
            echo "Unknown option $OPTARG"
            ;;
          ":")
            echo "No argument value for option $OPTARG"
            ;;
          *)
          # Should not occur
            echo "Unknown error while processing options"
            ;;
        esac
        echo "OPTIND is now $OPTIND"
      done
    

    getopts 命令使用了两个预先确定的变量。OPTIND 变量开始被设为 1。之后它包含待处理的下一个参数的索引。如果找到一个选项,则 getopts 命令返回 true,因此常见的选项处理范例使用带 case 语句的 while 循环,本例中就是如此。getopts 的第一个参数是一列要识别的选项字母,在本例中是 pr。选项字母后的冒号 (:) 表示该选项需要一个值;例如,-f 选项可能用于表示文件名,tar 命令中就是如此。此例中的前导冒号告诉 getopts 保持静默(silent)并抑制正常的错误消息,因为此脚本将提供它自己的错误处理。

    此例中的第二个参数 optname 是一个变量名,该变量将接收找到选项的名称。如果预期某个选项应该拥有一个值,而且目前存在该值,则会把该值放入 OPTARG 变量中。在静默模式下,可能出现以下两种错误情况。

    1. 如果发现不能识别的选项,则 optname 将包含一个 ? 而 OPTARG 将包含该未知选项。
    2. 如果发现一个选项需要值,但是找不到这个值,则 optname 将包含一个 : 而 OPTARG 将包含丢失参数的选项的名称。

    如果不是在静默模式,则这些错误将导致一条诊断错误消息而 OPTARG 不会被设置。脚本可能在 optname 中使用 ? 或 : 值来检测错误(也可能处理错误)。

    清单 6 给出了运行此简单脚本的两个示例。


    清单 6. 运行 testopt.sh 脚本
                    
    [ian@pinguino ~]$ ./testopt.sh -p -q
    OPTIND starts at 1
    Option p is specified
    OPTIND is now 2
    No argument value for option q
    OPTIND is now 3
    [ian@pinguino ~]$ ./testopt.sh -p -q -r -s tuv
    OPTIND starts at 1
    Option p is specified
    OPTIND is now 2
    Option q has value -r
    OPTIND is now 4
    Unknown option s
    OPTIND is now 5
    

    如果您需要这样做,可以传递一组参数给 getopts 计算。如果您在脚本中已经使用一组参数调用了 getopts,现在要用另一组参数来调用它,则需要亲自将 OPTIND 重置为 1。有关更多详细内容,请参阅 bash 手册或信息页面。





    回页首


    参数扩展

    您已经了解了如何将参数传递给函数或脚本以及如何识别选项,现在开始处理选项和参数。如果在处理选项后可以知道留下了哪些参数,那应该是一种不错的事情。接下来您可能需要验证参数值,或者为丢失的参数指派默认值。本节将介绍一些 bash 中的参数扩展。当然,您仍然拥有 Linux 或 UNIX 命令(如 sedawk)的全部功能来执行更复杂的工作,但是您也应该了解如何使用 shell 扩展。

    我们开始使用上述的选项分析和参数分析函数来构建一个脚本。清单 7 中给出了 testargs.sh 脚本。


    清单 7. testargs.sh 脚本
                    
    #!/bin/bash
    
    showopts () {
      while getopts ":pq:" optname
        do
          case "$optname" in
            "p")
              echo "Option $optname is specified"
              ;;
            "q")
              echo "Option $optname has value $OPTARG"
              ;;
            "?")
              echo "Unknown option $OPTARG"
              ;;
            ":")
              echo "No argument value for option $OPTARG"
              ;;
            *)
            # Should not occur
              echo "Unknown error while processing options"
              ;;
          esac
        done
      return $OPTIND
    }
    
    showargs () {
      for p in "$@"
        do
          echo "[$p]"
        done
    }
    
    optinfo=$(showopts "$@")
    argstart=$?
    arginfo=$(showargs "${@:$argstart}")
    echo "Arguments are:"
    echo "$arginfo"
    echo "Options are:"
    echo "$optinfo"
    

    尝试运行几次这个脚本,看看它如何运作,然后再对它进行详细考察。清单 8 给出了一些样例输出。


    清单 8. 运行 testargs.sh 脚本
                    
    [ian@pinguino ~]$ ./testargs.sh -p -q qoptval abc "def ghi"
    Arguments are:
    [abc]
    [def ghi]
    Options are:
    Option p is specified
    Option q has value qoptval
    [ian@pinguino ~]$ ./testargs.sh -q qoptval -p -r abc "def ghi"
    Arguments are:
    [abc]
    [def ghi]
    Options are:
    Option q has value qoptval
    Option p is specified
    Unknown option r
    [ian@pinguino ~]$ ./testargs.sh "def ghi"
    Arguments are:
    [def ghi]
    Options are:
    
    

    注意这些参数与选项是如何分开的。showopts 函数像以前一样分析选项,但是使用 return 语句将 OPTIND 变量的值返回给调用语句。调用处理将这个值指派给变量 argstart。然后使用这个值来选择原始参数的子集,原始参数包括那些没有被作为选项处理的参数。这个过程使用参数扩展
    ${@:$argstart} 来完成。
    记住在这个表达式的两侧使用引号使参数和嵌入空格保持在一起,如清单 2 后部所示。

    如果您是使用脚本和函数的新手,请记住以下说明:

    1. return 语句返回 showopts 函数的 exit 值,调用方使用 $? 来访问该函数。您也可以将函数的返回值和 testwhile 之类的命令结合使用来控制分支和循环。
    2. Bash 函数包括一些可选的词 —— “函数”,例如:
      function showopts ()
      这不是 POSIX 标准的一部分,不受 dash 之类的 shell 的支持,因此如果您要使用它,就不要将 shebang 行设为
      #!/bin/sh
      因为这会给您提供系统的默认 shell,而它可能不按您希望的方式运行。
    3. 函数输出,例如此处两个函数的 echo 语句所产生的输出,不会被打印出来,但是调用方可以访问该输出。如果没有将该输出指派给一个变量,或者没有在别的地方将它用作调用语句的一部分,则 shell 将会尝试执行输出而不是显示输出。

    子集和子字符串

    此扩展的一般形式为 ${PARAMETER:OFFSET:LENGTH},其中的 LENGTH 参数是可选参数。因此,如果您只希望选择脚本参数的特定子集,则可以使用完整版本来指定要选择多少个参数。例如,${@:4:3} 引用从参数 4 开始的 3 个参数,即参数 4、5 和 6。您可以使用此扩展来选择除那些使用 $1 到 $9 可立即访问的参数之外的单个参数。${@:15:1} 是一种直接访问参数 15 的方法。

    您可以将此扩展与单个参数结合使用,也可以与 $* 或 $@ 表示的整个参数集结合使用。在本例中,参数被作为一个字符串及引用偏移量和长度的数字来处理。例如,如果变量 x 的值为 “some value”,则
    ${x:3:5}
    的值就是 “e val”,如清单 9 所示。


    清单 9. shell 参数值的子字符串
                    
    [ian@pinguino ~]$ x="some value"
    [ian@pinguino ~]$ echo "${x:3:5}"
    e val
    

    长度

    您已经知道 $# 表示参数的数量,而 ${PARAMETER:OFFSET:LENGTH} 扩展适用于单个参数以及 $* 和 $@,因此,可以使用一个类似的结构体 ${#PARAMETER} 来确定单个参数的长度也就不足为奇了。清单 10 中所示的简单的 testlength 函数阐明了这一点。自己去尝试使用它吧。


    清单 10. 参数长度
                    
    [ian@pinguino ~]$ testlength () { for p in "$@"; do echo ${#p};done }
    [ian@pinguino ~]$ testlength 1 abc "def ghi"
    1
    3
    7
    

    模式匹配

    参数扩展还包括了一些模式匹配功能,该功能带有在文件名扩展或 globbing 中使用的通配符功能。注意:这不是 grep 使用的正则表达式匹配。

    表 2. Shell 扩展模式匹配
    扩展目的
    ${PARAMETER#WORD}shell 像文件名扩展中那样扩展 WORD,并从 PARAMETER 扩展后的值的开头删除最短的匹配模式(若存在匹配模式的话)。使用 ‘@’ 或 ‘$’ 即可删除列表中每个参数的模式。
    ${PARAMETER##WORD}导致从开头删除最长的匹配模式而不是最短的匹配模式。
    ${PARAMETER%WORD}shell 像文件名扩展中那样扩展 WORD,并从 PARAMETER 扩展后的值末尾删除最短的匹配模式(若存在匹配模式的话)。使用 ‘@’ 或 ‘$’ 即可删除列表中每个参数的模式。
    ${PARAMETER%%WORD}导致从末尾删除最长的匹配模式而不是最短的匹配模式。
    ${PARAMETER/PATTERN/STRING}shell 像文件名扩展中那样扩展 PATTERN,并替换 PARAMETER 扩展后的值中最长的匹配模式(若存在匹配模式的话)。为了在 PARAMETER 扩展后的值开头匹配模式,可以给 PATTERN 附上前缀 #,如果要在值末尾匹配模式,则附上前缀 %。如果 STRING 为空,则末尾的 / 可能被忽略,匹配将被删除。使用 ‘@’ 或 ‘$’ 即可对列表中的每个参数进行模式替换。
    ${PARAMETER//PATTERN/STRING}对所有的匹配(而不只是第一个匹配)执行替换。

    清单 11 给出了模式匹配扩展的一些基本用法。


    清单 11. 模式匹配示例
                    
    [ian@pinguino ~]$ x="a1 b1 c2 d2"
    [ian@pinguino ~]$ echo ${x#*1}
    b1 c2 d2
    [ian@pinguino ~]$ echo ${x##*1}
    c2 d2
    [ian@pinguino ~]$ echo ${x%1*}
    a1 b
    [ian@pinguino ~]$ echo ${x%%1*}
    a
    [ian@pinguino ~]$ echo ${x/1/3}
    a3 b1 c2 d2
    [ian@pinguino ~]$ echo ${x//1/3}
    a3 b3 c2 d2
    [ian@pinguino ~]$ echo ${x//?1/z3}
    z3 z3 c2 d2
    





    回页首


    整合

    在介绍其余要点之前,先来观察一下参数处理的实际示例。我构建了 developerWorks 作者程序包(有关 Linux 系统使用 bash 脚本的信息,请参阅 参考资料)。我们将所需的各种文件存储在 developerworks/library 库的子目录中。该库的最新发行版是 5.7 版,因此,模式文件位于 developerworks/library/schema/5.7 中、XSL 文件位于 developerworks/library/xsl/5.7 中,而示例模板则位于 developerworks/library/schema/5.7/templates 中。很明显,一个提供版本(本例中为 5.7)的参数即可满足脚本构建指向所有这些文件的路径的需要。因此脚本获取的 -v 参数必须有值。稍后对这个参数执行验证,方法是构建路径然后使用 [ -d "$pathname" ] 检查它是否存在。

    这种方法对产品构建而言非常有效,但是在开发期间,文件被存储在不同的目录中:

    • developerworks/library/schema/5.8/archive/test-5.8/merge-0430
    • developerworks/library/xsl/5.8/archive/test-5.8/merge-0430 和
    • developerworks/library/schema/5.8/archive/test-5.8/merge-0430/templates-0430

    这些目录中的当前版本为 5.8,0430 则表示最新测试版本的日期。

    为了处理这一情况,我添加了一个参数 -p,它包含了一段补充的路径信息 —archive/test-5.8/merge-0430。现在,我(或者别的什么人)可能忘记了前导斜杠或末尾斜杠,而一些 Windows 用户可能使用反斜杠而不是正斜杠,因此我决定在脚本中对此进行处理。另外,您还注意到指向模板目录的路径包含了两次日期,因此需要在运行时设法摘除日期 0430。

    清单 12 给出了用来处理两个参数和根据这些需求清理部分路径的代码。-v 选项的值存储在 ssversion 变量中,清理后的 -p 变量存储在 pathsuffix 中,而日期(连同前导连字符)则存储在 datesuffix 中。注释解释了每一步执行的操作。即使在这样一小段脚本中,您也可以找到一些参数扩展,包括长度、子字符串、模式匹配和模式替换。


    清单 12. 分析用于 developerWorks 作者程序包构建的参数
                    
    while getopts ":v:p:" optval "$@"
      do
        case $optval in
          "v")
            ssversion="$OPTARG"
          ;;
          "p")
            # Convert any backslashes to forward slashes
            pathsuffix="${OPTARG//\\//}"
            # Ensure this is a leading / and no trailing one
            [ ${pathsuffix:0:1} != "/" ] && pathsuffix="/$pathsuffix"
            pathsuffix=${pathsuffix%/}
            # Strip off the last hyphen and what follows
            dateprefix=${pathsuffix%-*}
            # Use the length of what remains to get the hyphen and what follows
            [ "$dateprefix" != "$pathsuffix" ] && datesuffix="${pathsuffix:${#dateprefix}}"
            ;;
          *)
            errormsg="Unknown parameter or option error with option - $OPTARG"
            ;;
        esac
      done
    

    像 Linux 中的大多数内容一样,也许通常对编程而言,这并非解决此问题的惟一解决方案,但它确实展示了您了解的扩展的一种更实际的用法。





    回页首


    默认值

    在上一节中您已经了解了如何为 ssversion 或 pathsuffix 之类的变量指派选项值。在这种情况下,稍后将检测到空值,产品构建时会出现空路径后缀,因此这是可以接受的。如果需要为尚未指定的参数指派默认值怎么办?表 3 所示的 shell 扩展将帮助您完成这个任务。

    表 3. 默认值相关的 Shell 扩展
    扩展目的
    ${PARAMETER:-WORD}如果 PARAMETER 没有设置或者为空,则 shell 扩展 WORD 并替换结果。PARAMETER 的值没有更改。
    `${PARAMETER:=WORD}如果 PARAMETER 没有设置或者为空,则 shell 扩展 WORD 并将结果指派给 PARAMETER。这个值然后被替换。不能用这种方式指派位置参数或特殊参数的值。
    ${PARAMETER:?WORD}如果 PARAMETER 没有设置或者为空,shell 扩展 WORD 并将结果写入标准错误中。如果没有 WORD 则写入一条消息。如果 shell 不是交互式的,则表示存在这个扩展。
    ${PARAMETER:+WORD}如果 PARAMETER 没有设置或者为空,则不作替换。否则 shell 扩展 WORD 并替换结果。

    清单 13 演示了这些扩展以及它们之间的区别。


    清单 13. 替换空变量或未设置的变量。
                    
    [ian@pinguino ~]$ unset x;y="abc def"; echo "/${x:-'XYZ'}/${y:-'XYZ'}/$x/$y/"
    /'XYZ'/abc def//abc def/
    [ian@pinguino ~]$ unset x;y="abc def"; echo "/${x:='XYZ'}/${y:='XYZ'}/$x/$y/"
    /'XYZ'/abc def/'XYZ'/abc def/
    [[ian@pinguino ~]$ ( unset x;y="abc def"; echo "/${x:?'XYZ'}/${y:?'XYZ'}/$x/$y/" )\
    >  >so.txt 2>se.txt
    [ian@pinguino ~]$ cat so.txt
    [ian@pinguino ~]$ cat se.txt
    -bash: x: XYZ
    [[ian@pinguino ~]$ unset x;y="abc def"; echo "/${x:+'XYZ'}/${y:+'XYZ'}/$x/$y/"
    //'XYZ'//abc def/
    





    回页首


    传递参数

    关于参数传递有一些微妙之处,如果不小心,可能会犯错误。您已经了解了使用引号的重要性以及引号对使用 $* 和 $@ 的影响,但是考虑以下的例子。假设您想要一个脚本或函数来操作当前工作目录中的所有文件或目录。为了说明这个例子,考虑清单 14 所示的 ll-1.sh 和 ll-2.sh 脚本。


    清单 14. 两个示例脚本
                    
    #!/bin/bash
    # ll-1.sh
    for f in "$@"
      do
        ll-2.sh "$f"
      done
    
    #!/bin/bash
    ls -l "$@"
    

    脚本 ll-1.sh 只是将它的每个参数依次传递给脚本 ll-2.sh 而 ll-2.sh 执行传递的参数的一个长目录清单。我的测试目录包含了两个空文件 “file1” 和 “file 2”。清单 15 显示了脚本的输出。


    清单 15. 运行脚本 - 1
                    
    [ian@pinguino test]$ ll-1.sh *
    -rw-rw-r-- 1 ian ian 0 May 16 15:15 file1
    -rw-rw-r-- 1 ian ian 0 May 16 15:15 file 2
    

    到目前为止,一切进展得还不错。但是如果您忘记使用 * 参数,则脚本不会执行任何操作。它不会像 ls 命令那样自动执行当前工作目录的内容。可以做一个简单的修正,当没有给 ll1-sh 提供数据时为 ll-1.sh 中的这个条件添加检查并使用 ls 命令的输出来生成 ll-2.sh 的输入。清单 16 给出了一个可能的解决方案。


    清单 16. 修正后的 ll-1.sh
                    
    #!/bin/bash
    # ll-1.sh - revision 1
    for f in "$@"
      do
        ll-2.sh "$f"
      done
    [ $# -eq 0 ] && for f in "$(ls)"
      do
        ll-2.sh "$f"
      done
    

    注意:我们小心地将 ls 命令的结果用引号引用起来,确保可以正确地处理 “file 2”。清单 17 给出了运行带 * 和不带 * 的新 ll-1.sh 的结果。


    清单 17. 运行脚本 - 2
                    
    [ian@pinguino test]$ ll-1.sh *
    -rw-rw-r-- 1 ian ian 0 May 16 15:15 file1
    -rw-rw-r-- 1 ian ian 0 May 16 15:15 file 2
    [ian@pinguino test]$ ll-1.sh
    ls: file1
    file 2: No such file or directory
    

    很奇怪吧?当您传递参数时,尤其当这些参数是命令的输出时,处理起来可能需要些技巧。错误消息提示文件名被换行符分隔,这就给我们提供了线索。有很多种方法可以处理这个问题,但是有一种简单的方法就是,使用清单 18 所示的内置 read。自己可以试用一下。


    清单 17. 运行脚本 - 2
                    
    #!/bin/bash
    # ll-1.sh - revision 2
    for f in "$@"
      do
        ll-2.sh "$f"
      done
    [ $# -eq 0 ] && ls | while read f
      do
        ll-2.sh "$f"
      done
    

    这个例子的目的就是要说明:注意细节并使用一些不常见的输入来进行测试可以使脚本更加可靠。祝您编程顺利!





    回页首


    结束语

    分享这篇文章......

    digg 将本文提交到 Digg
    del.icio.us 发布到 del.icio.us
    Slashdot 提交到 Slashdot!

    如果您想了解有关 Linux 中 bash 脚本编程的更多内容,请阅读教程 “LPI 102 考试准备,主题 109: Shell、脚本、编程和编译”,本文中的某些内容就是摘录自该教程。要了解有关一些其他可用来分析文本(如参数值)的命令,请参阅教程 “LPI 101 考试准备: GNU 和 UNIX 命令”,您可以找到下面的其他 参考资料。最后,别忘了 对本文进行评价



    参考资料

    学习

    获得产品和技术
    • 请订购 SEK for Linux,共有两张 DVD,包含最新的用于 Linux 的 IBM 试用软件,包括 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere®。

    • 使用可直接从 developerWorks 下载的 IBM 试用软件 构建您的下一个 Linux 开发项目。


    讨论


    关于作者

    Ian Shields

    Ian Shields 为 developerWorks Linux 专区的许多 Linux 项目工作。他是 IBM 北卡罗莱那州 Research Triangle Park 的一名高级程序员。他于 1973 年作为一名系统工程师加入 IBM 位于澳大利亚堪培拉的子公司。之后,在加拿大蒙特利尔和北卡罗莱那州 RTP 从事通信系统和普及运算。他拥有多项专利并发表了若干篇论文。他毕业于 Australian National University,本科学位是纯数学和哲学。他拥有北卡罗来纳州立大学的计算机硕士和博士学位。

    转载于:https://www.cnblogs.com/licheng/archive/2008/08/05/1261086.html

    展开全文
  • bash参数

    2016-05-18 20:52:48
    一个参数是一个存储值的实体。它可以是一个名称,号码,或根据特殊参数下面列出的特殊字符中的一个。变量是一个名称代表的参数。一个变量有值和零个或多个属性。属性是使用内建命令declare命令分配.如果已分配一个值...

    一个参数是一个存储值的实体。它可以是一个名称,号码,或根据特殊参数下面列出的特殊字符中的一个。变量是一个名称代表的参数。一个变量有值和零个或多个属性。属性是使用内建命令declare命令分配.

    如果已分配一个值的参数设置。空字符串是一个有效的值。一旦一个变量被设置,它可能只使用未设置内置命令取消设置.

    name=[value]
    不执行路径扩展。赋值语句也可能出现作为参数传递给别名,声明,排版,输出,只读,和当地的内建命令。

    在POSIX模式时,这些内建可内建的命令的一个或多个实例后出现在命令并保留这些赋值语句的属性。

    在一个赋值语句赋值给一个shell变量或数组索引的情况下,+=运算符可以用来追加或添加变量的前值。当+ =施加的量,整数属性已经设置的变量,值被评价为一个算术表达式,并加到变量的当前值,其也被评估。当+=使用复合赋值(见下文数组)应用到一个数组变量,该变量的值不是取消设置(因为它是一个使用=的话)和新值追加到数组从1开始比数组的最大折射率(用于索引数组),或者添加为关联数组附加键 - 值对。当施加到字符串值的变量,值被扩展并追加到变量的值。

    一个变量可以被分配使用-n选项来申报或本地内置命令的nameref属性(参见申报及以下地方的描述)创建nameref,或其他变量的引用。

    这使得变量间接操纵。

    一个变量可以被分配使用-n选项来申报或本地内置命令的nameref属性(参见申报及以下地方的描述)创建nameref,或其他变量的引用。这使得变量间接操纵。每当nameref变量被引用或分配给时,操作实际上是由nameref变量的值所指定的变量进行。一个nameref通常shell函数中用来指代其名称作为参数传递给函数传递一个变量。例如,如果一个变量名被传递给shell函数作为第一个参数,运行
    declare -n ref= 1REF 1传递的变量。如果循环中的控制变量具有nameref属性,词语的列表可以是壳变量的列表,并且在执行循环时的名称将参考建立在列表中的每个字,反过来。然而,nameref变量可以引用数组变量和标数组变量。否则,如果未设置与nameref变量作为参数的名称执行,由nameref变量引用的变量将取消设置。
    当由比单个数字位置参数展开时,它必须用括号括起来

    展开全文
  • bash脚本传递参数

    2019-11-21 21:47:09
    /bin/bash #set接受参数 v_user="" v_pwd="" v_table="" v_date=$(date -d"-1 days" +"%Y%m%d") #接收可选参数 while getopts :u:p:t:d: opt do case "$opt" in u) v_user=$OPTARG;; p) v_pwd=$OPTARG;; t) v...
    #!/bin/sh
    
    HOST=localhost
    PORT=8848
    USER=root
    PASSWD=root
    
    echo "HOST=${HOST} PORT=${PORT} USER=${USER} PASSWD=${PASSWD}"
    while getopts ":H:P:u:p:" opt
    do
        case $opt in
            H)
                HOST=$OPTARG;;
            P)
                PORT=$OPTARG;;
            u)
                USER=$OPTARG;;
            p)
                PASSWD=$OPTARG;;
            ?)
                echo "Unknown parameter"
                exit 1;;
        esac
    done
    
    echo "HOST=${HOST} PORT=${PORT} USER=${USER} PASSWD=${PASSWD}"
    
    
    
    #!/bin/bash
    #testPa.sh -uxxx -pxxx -txxx -dyyyyyMMdd
    
    #set接受参数
    v_user=""
    v_pwd=""
    v_table=""
    v_date=$(date -d"-1 days" +"%Y%m%d")
    
    #接收可选参数
    while getopts :u:p:t:d: opt
    do
      case "$opt" in
      u) v_user=$OPTARG;; 
      p) v_pwd=$OPTARG;;
      t) v_table=$OPTARG;;
      d) v_date=$OPTARG;;
      *) echo "Unknown option: $opt" ;;
      esac
    done
    
    echo "v_user=${v_user} v_pwd=${v_pwd} v_table=${v_table} v_date=${v_date}"
    
    shift $[ $OPTIND - 1 ]
    
    #进入脚本目录
    #cd $(dirname $0)
    echo $(dirname $0)
    
    #获取根目录
    #BASEHOME=$(dirname $PWD)
    echo $(dirname $PWD)
    
    [root@VM_0_11_centos test]# pwd
    /root/test
    [root@VM_0_11_centos test]# bash testPa.sh 
    v_user= v_pwd= v_table= v_date=20191120
    .
    /root
    [root@VM_0_11_centos test]# 
    

    #!/bin/bash
    echo $*
    while getopts ":a:bc:" opt
    do
    	case $opt in
    		a) echo $OPTARG $OPTIND;;
    		b) echo "b $OPTIND";;
    		c) echo "c $OPTIND";;
    		?) echo "error";
    		   exit 1;;
    	esac
    done
    echo $OPTIND
    shift $(( $OPTIND-1 ))
    echo $0
    echo $*
    
    [root@VM_0_11_centos test]# /root/test/test2.sh -aaaa -bbbb -cccc
    -aaaa -bbbb -cccc
    aaa 2
    b 2
    b 2
    b 2
    b 3
    c 4
    4
    /root/test/test2.sh
    结果这里有一个空行
    

    custom1.list文件内容

    [N01] michael 1001
    [N02] bob 1002
    [N02] michelle 1003
    

    bash读取配置文件

    #!/bin/bash
    
    while group name id
    do
    	echo "${group} === ${name} === ${id}"
    done < /root/custom1.list
    
    [N01] === michael === 1001
    [N02] === bob === 1002
    [N02] === michelle === 1003
    

    getopts的使用
    语法格式:
    getopts [option[:]] [DESCPRITION] VARIABLE
    option :表示为某个脚本可以使用的选项
    ":" :如果某个选项(option)后面出现了冒号(":"),则表示这个选项后面可以接参数(即一段描述信息DESCPRITION)
    VARIABLE :表示将某个选项保存在变量VARIABLE中
     
    getopts :是linux系统中的一个内置变量,一般用在循环中。每当执行循环是,getopts都会检查下一个命令选项,如果这些选项出现在option中,则表示是合法选项,否则不是合法选项。并将这些合法选项保存在VARIABLE这个变量中。
    getopts :还包含两个内置变量,及OPTARG和OPTIND
    OPTARG :就是将选项后面的参数(或者描述信息DESCPRITION)保存在这个变量当中。
    OPTIND :这个表示命令行的下一个选项或参数的索引(文件名不算选项或参数)
    
    ---------------------------------------------------
    #!/bin/bash
    while getopts ':b:d:' OPT &> /dev/null;do
    	case $OPT in
    		b)
    		echo "The options is b"
    		echo $OPTARG ;;
    		d)
    		echo "The options is d"
    		echo $OPTARG ;;
    		*)
    		echo "Wrong Options"
    		exit 7 ;;
    	esac
    	# echo $OPT
    	# echo $OPTARG
    done
    echo $OPTIND
    shift $[$OPTIND-1]
    echo $1
    
    ----------------------------------------------------------
    ###执行脚本时,显示的结果如下###
    [root@localhost scriptTEAM]# ./test -d 'nice' fixnale
    The options is d  
    nice
    3
    fixnale
    ###显示信息说明如下###
    当输入-d时,$OPT=d,$OPTARG='nice',因此就会显示d)...这一部分的信息。
    由于这里有一个选项(-d)和一个参数('nice'),$OPTIND指向命令行中下一个选项或参数的索引位置,因此这里即为3。
    shift $[$OPTIND-1]表示将文件名前面的选项和参数踢掉
    
    =============================================================================================================
    
    [root@localhost ~]# cat getopts.sh
    #!/bin/bash
    echo $*
    while getopts ":a:bc:" opt
    do
        case $opt in
            a) echo $OPTARG $OPTIND;;
            b) echo "b $OPTIND";;
            c) echo "c $OPTIND";;
            ?) echo "error" 
    		   exit 1;;
        esac
    done
    echo $OPTIND
    shift $(( $OPTIND-1 ))
    echo $0
    echo $*
    -----------------------------------------------------
    [root@localhost ~]# sh getopts.sh -a 11 -b -c 6
    -a 11 -b -c 6
    11 3
    b 4
    c 6
    6
    getopts.sh
    --------------------------------------------------
    
    
    为什么会得到上面的结果呢?
    
    while getopts ":a:bc:" opt #第一个冒号表示忽略错误;字符后面的冒号表示该选项必须有自己的参数。
    
    $OPTARG 存储相应选项的参数,如上例中的11、6;
    
    $OPTIND 总是存储原始$*中下一个要处理的选项(不是参数,而是选项,此处指的是a,b,c这三个选项,而不是那些数字,当然数字也是会占有位置的)位置。
    
    optind初值为1,遇到"x",选项不带参数,optind+=1;遇到"x:",带参数的选项,optarg=argv[optind+1],optind+=2;遇到"x::",可选参数,属于#1和#2之一(转载过来的,这句我也看不懂)
    
    第一行输出echo $*
    第二行,optind初值为1,选项-a的参数为11,下一个要处理的选项-b位置为3,所以输出:11 3;
    第三行,然后-b要处理的下一个选项-c位置为4,所以输出:b 4;
    第四行,再者-c有参数,所以下一个要处理的位置+2,所以输出:c 6;
    
    
    ------------------------------------------------------------------
    [root@localhost ~]# sh getopts.sh -a 11 -b -b 9 -c 6
    -a 11 -b -b 5 -c 6
    11 3
    b 4
    b 5
    5
    getopts.sh
    9 -c 6
    ------------------------------------------------------------
    起初我看到以上的输出结果百思不得其解,后面多试几次选项及参数后,大概猜了一下。
    第一行输出echo $*
    第二行,optind初值为1,下一个要处理的选项-b位置为3,所以输出11 3;
    第三行,下一个要处理的选项-b位置为4,所以输出b 4;
    第四行,下一个要处理的选项-b位置为5,所以输出b 5;
    程序现在遇到9,不属于getopts,所以停止循环while,下面几行就不解释了。
    getopt 与 getopts 都是 Bash 中用来获取与分析命令行参数的工具,常用在 Shell 脚本中被用来分析脚本参数。
    
    两者的比较
    (1)getopts 是 Shell 内建命令,getopt 是一个独立外部工具
    (2)getopts 使用语法简单,getopt 使用语法较复杂
    (3)getopts 不支持长参数(如:--option ),getopt 支持
    (4)getopts 不会重排所有参数的顺序,getopt 会重排参数顺序(这里的区别下面会说明)
    (5)getopts 出现的目的是为了代替 getopt 较快捷的执行参数分析工作
    
    
    
    
    
    
    
    展开全文
  • BASH SHELL 接受参数

    万次阅读 2012-08-31 09:27:38
    原文地址:http://www.ibm.com/developerworks/cn/linux/l-bash-parameters.html ...通过本文,您将了解到如何在 bash 脚本中处理参数和选项,以及如何使用 shell 的参数扩展检查或修改参数。本文重点介绍
  • 级 别: 中级 Ian Shields, 高级程序员, IBM  2007 年 7 月 30 日 ...您是否 有时想知道如何对脚本使用参数,以及如何...本文将向您介绍参数的用法和 bash shell 中的各种参数扩展。 现在,很多 Linux? 和 UN
  • 通过本文,您将了解到如何在 bash 脚本中处理参数和选项,以及如何使用 shell 的参数扩展检查或修改参数。本文重点介绍 bash,文中的示例都是在以 bash 为 shell 的 Linux 系统上运行。但是,很多其他的 shell 中也...
  • Shell 不提供数组,Bash 提供了一维索引数组和一维的关联数组。 索引数组 什么是索引数组?通过整数索引访问的数组就是索引数组。例如 echo $arr[0] 在 Bash 中,数组创建的方式很奇怪,我们可以不声明数组变量,...
  • bash内建命令索引

    2019-01-29 19:36:52
    不做任何事,只做参数展开 . 读取文件并在当前shell中执行 alias 设置命令或命令行的别名 bg 将作业至于后台执行 bind ...
  • Bashhub保存在所有会话和系统中输入的每个终端命令,并提供对所有命令的强大查询。 产品特点 通过使用有关如何执行命令的上下文来搜索超级命令。 例如目录,会话,系统,退出状态等。... 在任何bh搜索中添加-i参数
  • GitHub教程 Git Bash详细教程

    万次阅读 多人点赞 2018-01-17 16:12:58
    作为一个萌新,我翻遍了网上的Git Bash教程,可能因为我理解力比较差,经常看不懂教程上在说什么。 (。-`ω´-)所以我决定自己一边摸索一边记录,写教程造福那些理解力跟我一样差的人…… 第一篇教程会涉及...
  • BASH

    2019-10-07 21:10:53
    centos默认使用bash bash的优点 历史命令记录功能,记录文件为 ~/.bash_history 命令与文件补全功能 [Tab] 接在一串指令的第一个字的后面,则为命令补全; [Tab] 接在一串指令的第二个字...
  • BASH_EXECUTION_STRING BASH_LINENO BASH_REMATCH BASH_SOURCE BASH_SUBSHELL BASH_VERSINFO BASH_VERSION COMP_CWORD COMP_KEY COMP_LINE COMP_POINT COMP_TYPE COMP_WORDBREAKS COMP_WORDS COPROC DIRSTACK EUID ...
  • bash 数组

    2016-05-23 21:51:14
    Bash提供一维标和关联数组变量。任何变量也可以用作索引数组;内建命令declare将明确地声明数组。有上数组的大小,也没有成员索引或者连续赋值的要求没有上限。索引数组使用整数(包括算术表达式)引用并zerobased;...
  • Bash编程

    2019-02-18 16:45:23
    本文介绍了bash脚本编写的相关内容,文末有一些示例。 文章目录一、bash脚本介绍1. shell2. bash脚本二、bash脚本基础1. 编程语言分类2. 编写代码的约定三、bash语法介绍1. 变量bash中的变量类型变量声明本地变量的...
  • sqlite_lib.bash Bash库在bash脚本中使用SQLite 依存关系: sqlite3 在ArchLinux上使用sqlite ... 第一个索引是行结果索引,第二个索引是结果数据的列名称 for (( i = 0 ; i < num_rows; i ++ )) ; do echo
  • Bash语法

    2020-04-13 18:45:53
    Shell简介 shell是一种脚本语言,...不过shell也分化出了很多种类,常见的有shell(/bin/sh)、bash(/bin/bash)、csh(/usr/bin/csh)、ksh(/usr/bin/ksh)、powershell(windows的shell)等,大部分shell语法互相兼容,其...
  • bash编程

    万次阅读 2020-10-11 15:44:17
    } f a b c d e f g h # 传参数 p1=a p2=b p3=a b c d e f g h p4=8 p5=8 f(){ > wc -l $@ # $@是要传进来的参数 > } bash 1.sh 1.txt # bash是执行1.sh文件 1.txt是传进去的参数 chmod +x 1.sh 添加权限,给所有都...
  • bash基础

    2011-01-11 11:33:00
    12/29/2010 胡浩轩译目录表索引:1. 为什么要指导2. 谁需要读这本书3. 新版本及可用性4. 版本历史5. 贡献价值6. 反馈7. 版权信息8. 读者所需要的9. 文档中用到的约定俗成10.文档组织第一章 Bash...
  • Bash变量

    2019-06-11 16:07:33
    这些变量由Bash设置或使用,但其他shell通常不会特别对它们进行处理。 Bash使用的一些变量在不同的章节中...列表中的每个单词都是有效的参数-sshopt内置命令的选项 (请参阅Shopt Builtin)。出现的选项BASHOPTS是...
  • bash 运行文件#!bin/bash

    千次阅读 2020-10-18 18:04:17
    1 如何使用Chmod使Bash脚本可执行 引用自参考文献【1】 在本教程中,我将逐步介绍创建bash脚本并使用chmod命令使脚本可执行的步骤。之后,无需使用sh或bash命令就可以运行它。 步骤1: 创建一个Bash文件 首先是.sh...
  • bash数组

    2017-03-03 17:51:26
    数组是包含多个相同或不同数据类型的集合,数组索引从零开始。本文有 15 个用 bash 操作数组的例子。 1. 声明数组,赋值 当有变量为如下格式的时候,Bash 会自动创建数组。 name[index]=value name ...
  • Bash数组

    2012-08-28 10:59:00
    Bash数组 1.描述 Bash的数组,其元素的个数没有限制。数组的索引由0开始,但不一定要 连续(可以跳号)。索引也可以算术表达式。bash仅支持一维数组。 1.1 declare 名称:设置变量和属性(可以用来声明一个...
  • Bash: Bash详解

    千次阅读 2014-09-20 19:08:03
    Bash(详解)http://www.linuxmine.com/3855.html2005-08-24 10:00 am作者:linux宝库 (http://www.linuxmine.com)来自:linux宝库 (http://www.linuxmine.com)联系:linuxmine#gmail.com最简单的例子 —— Hello ...
  • bash命令

    2019-05-13 19:40:37
    1. Basic Operations a.export 显示所有的环境变量,如果你想获取某个变量的详细信息,使用echo $VARIABLE_NAME. export Example: $ export SHELL=/bin/zsh AWS_HOME=/Users/adnanadnan/.aws ...LES...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 26,308
精华内容 10,523
关键字:

bash索引参数