【问题标题】:How to pass all arguments passed to my bash script to a function of mine? [duplicate]如何将传递给我的 bash 脚本的所有参数传递给我的函数? [复制]
【发布时间】:2011-04-18 04:51:07
【问题描述】:

假设我定义了一个function abc(),它将处理与分析传递给我的脚本的参数相关的逻辑。

如何将我的 bash 脚本收到的所有参数传递给它?参数的数量是可变的,所以我不能像这样硬编码传递的参数:

abc $1 $2 $3 $4

编辑。更好的是,我的函数有什么方法可以访问脚本参数的变量吗?

【问题讨论】:

  • Propagate all arguments in a bash shell script 的可能重复项。 (这个问题实际上是在此处链接的问题之前发布的。但链接中的问题具有更详细的答案和更丰富的标题,可能最好作为参考问题)

标签: bash function parameter-passing


【解决方案1】:

$@ 变量扩展为所有由空格分隔的命令行参数。这是一个例子。

abc "$@"

在使用$@ 时,您应该(几乎)始终将其放在双引号中以避免错误解析包含空格或通配符的参数(见下文)。这适用于多个参数。它还可以移植到所有符合 POSIX 标准的 shell。

另外值得注意的是$0(一般是脚本的名称或路径)不在$@中。

Bash Reference Manual Special Parameters Section 表示$@ 扩展为从一开始的位置参数。当扩展出现在双引号内时,每个参数都扩展为一个单独的单词。即"$@" 等价于"$1" "$2" "$3"...

传递一些参数:

如果您想传递除第一个以外的所有参数,您可以首先使用shift 来“使用”第一个参数,然后传递"$@" 以将剩余的参数传递给另一个命令。在 bash(以及 zsh 和 ksh,但不是在像 dash 这样的普通 POSIX shell 中)中,您可以使用数组切片的变体来执行此操作而不会弄乱参数列表:"${@:3}" 将为您提供以 "$3" 开头的参数。如果传递了那么多参数,"${@:3:4}" 将为您提供从 "$3" 开始的最多四个参数(即"$3" "$4" "$5" "$6")。

你可能不想做的事情:

"$*" 将所有参数组合成一个字符串(由空格分隔,或者$IFS 的第一个字符是什么)。这失去了空格 within 参数和空格 between 参数之间的区别,因此通常是一个坏主意。尽管打印参数可能没问题,例如echo "$*",前提是您不关心保留区别内/之间的空间。

将参数分配给常规变量(如args="$@")会像"$*" 那样将所有参数混合在一起。如果要将参数存储在变量中,请使用带有args=("$@") 的数组(括号使其成为数组),然后将它们引用为例如"${args[0]}" 等请注意,在 bash 和 ksh 中,数组索引从 0 开始,因此 $1 将在 args[0] 等中。另一方面,zsh 从 1 开始数组索引,因此 $1 将是在args[1]。像 dash 这样更基本的 shell 根本没有数组。

省略双引号,使用$@$*,将尝试将每个参数拆分为单独的单词(基于空格或$IFS 中的任何内容),并尝试扩展任何看起来就像文件名通配符到匹配文件名列表中一样。这可能会产生非常奇怪的影响,并且几乎应该始终避免。 (除了在 zsh 中,默认情况下不会发生这种扩展。)

【讨论】:

  • 阅读更多关于为什么在此处使用双 " 很重要:stackoverflow.com/a/4824637/4575793
  • "${@:3}" 似乎不适用于zsh
  • 额外注释:$* 将是一个字符串,IFS 的第一个字符是连接元素。
  • @kvantour 如果$* 用双引号括起来,就会发生这种情况。如果它没有被引用,它会受到分词和通配符扩展的影响,因此它会立即重新拆分回元素 并且 任何包含 $IFS 字符的元素也将被拆分(然后任何通配符都会被拆分)展开)。最终结果:没有双引号,$*$@ 最终给出相同的结果。
  • @DylanYoung 您必须解析它们以确定哪些应该被视为选项参数。例如,在somecmd -a b c -d 中,-a 显然是一个选项,但b-a 的一个参数(因此是它的“一部分”),还是一个简单的位置参数?你需要知道-a 是否需要一个参数来决定。此外,如果 - 在第一个位置命令之前,某些命令仅将其识别为指示选项,因此 -d 可能是也可能不是选项,具体取决于此命令使用的策略。
【解决方案2】:

我需要对此进行修改,希望对其他人有用:

function diffs() {
        diff "${@:3}" <(sort "$1") <(sort "$2")
}

"${@:3}" 部分表示从 3 开始的数组的所有成员。所以这个函数通过将前两个参数通过 sort 传递给 diff,然后将所有其他参数传递给 diff 来实现排序的 diff,所以你可以调用它类似于 diff:

diffs file1 file2 [other diff args, e.g. -y]

【讨论】:

  • "${@:3}" 在您的脚本有参数时也很棒,但也可以将参数传递给它们调用的其他脚本。例如,我的一个项目有一个用于轻松运行程序的脚本,并带有一个供主类使用的参数。然后"${@:2}" 可用于将剩余的参数传递给该入口点。
  • @Kat 已经提到了这一点,但要澄清一下(以防您仍有疑问):command "$@" 等同于command $1 "${@:2}"
  • 天啊!我你!
【解决方案3】:

使用$@ 变量,该变量扩展为所有由空格分隔的命令行参数。

abc "$@"

【讨论】:

    【解决方案4】:

    这是一个简单的脚本:

    #!/bin/bash
    
    args=("$@")
    
    echo Number of arguments: $#
    echo 1st argument: ${args[0]}
    echo 2nd argument: ${args[1]}
    

    $# 是脚本接收的参数数量。我发现使用数组更容易访问它们:args=("$@") 行将所有参数放在args 数组中。要访问它们,请使用${args[index]}

    【讨论】:

    • 第一个参数是${args[0]} :o
    • 将 $@ 传递到数组中比仅按索引调用参数(例如,$1)有什么好处?
    • 投票同意与@King 的协议,即第一个元素需要在 [0] 处作为数组。
    • 不知何故我错过了它。已修复,谢谢指出。
    • 未来的读者应该注意这个例子中的shebang是不正确的。 sh 不支持数组,这是一个 bash 功能。这可能起作用的唯一原因是,如果您的操作系统已将 /bin/sh 符号链接到 bash,或者您使用 bash script.sh 调用脚本。
    【解决方案5】:

    值得一提的是,您可以使用此语法指定参数范围。

    function example() {
        echo "line1 ${@:1:1}"; #First argument
        echo "line2 ${@:2:1}"; #Second argument
        echo "line3 ${@:3}"; #Third argument onwards
    }
    

    我没看到有人提到过。

    【讨论】:

    • 前两个可以使用$1, $2,...
    • @rubo77 我已经更正了答案的措辞,包括“范围”谢谢。
    • 谢谢,这正是我用变量索引$@ 所需要的
    【解决方案6】:

    abc "$@" 通常是正确的答案。 但是我试图将参数传递给 su 命令,并且没有多少引用可以阻止错误su: unrecognized option '--myoption'。实际上对我有用的是将所有参数作为单个字符串传递:

    abc "$*"
    

    我的确切情况(我确定其他人需要这个)在我的 .bashrc 中

    # run all aws commands as Jenkins user
    aws ()
    {
        sudo su jenkins -c "aws $*"
    }
    

    【讨论】:

    • 嘿,OP,看起来你在 abc 示例中可能有错字
    • 正是我需要的。我的命令用引号括起来,这是唯一对我有用的东西。
    • 大概是这样的使用方式,但要注意使用字符串参数时的风险。请在此处查看“$*”示例:stackoverflow.com/a/46205560/4575793(更多关于 '$@' 与 '$*' 以及引用的变体)
    【解决方案7】:
    abc "$@"
    

    $@ 表示为您的 bash 脚本提供的所有参数。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-05
    • 1970-01-01
    • 2021-11-18
    • 2012-12-29
    • 1970-01-01
    • 2012-01-23
    相关资源
    最近更新 更多