有没有办法避免bash中的位置参数?

Bhu*_*han 51 bash shell scripting

我必须在bash中编写一个函数.该函数将需要大约7个参数.我知道我可以调用这样的函数:

要使用参数调用函数:

function_name $arg1 $arg2
Run Code Online (Sandbox Code Playgroud)

我可以在函数中引用我的参数:

function_name () {
   echo "Parameter #1 is $1"
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,有没有更好的方法参考函数内部的参数?我可以避免$ 1,$ 2,$ 3,......的事情,只需使用$ arg1,$ arg2,......?

是否有适当的方法或我是否需要将这些参数重新分配给函数内的其他变量?例如:

function_name () {
   $ARG1=$1
   echo "Parameter #1 is $ARG1"
}
Run Code Online (Sandbox Code Playgroud)

任何例子都将非常感激.

Mic*_*rny 69

这样做的常用方法是将参数分配给函数中的局部变量,即:

copy() {
    local from=${1}
    local to=${2}

    # ...
}
Run Code Online (Sandbox Code Playgroud)

另一种解决方案可能是getopt- style选项解析.

copy() {
    local arg from to
    while getopts 'f:t:' arg
    do
        case ${arg} in
            f) from=${OPTARG};;
            t) to=${OPTARG};;
            *) return 1 # illegal option
        esac
    done
}

copy -f /tmp/a -t /tmp/b
Run Code Online (Sandbox Code Playgroud)

可悲的是,庆典不能处理长选项,这些选项是更具可读性,即:

copy --from /tmp/a --to /tmp/b
Run Code Online (Sandbox Code Playgroud)

为此,您需要使用外部getopt程序(我认为只有GNU系统支持长选项)或者手动实现长选项解析器,即:

copy() {
    local from to

    while [[ ${1} ]]; do
        case "${1}" in
            --from)
                from=${2}
                shift
                ;;
            --to)
                to=${2}
                shift
                ;;
            *)
                echo "Unknown parameter: ${1}" >&2
                return 1
        esac

        if ! shift; then
            echo 'Missing parameter argument.' >&2
            return 1
        fi
    done
}

copy --from /tmp/a --to /tmp/b
Run Code Online (Sandbox Code Playgroud)

另请参阅:在bash shell脚本中使用getopts来获取长和短命令行选项


你也可以是懒惰的,只需将'variables'作为参数传递给函数,即:

copy() {
    local "${@}"

    # ...
}

copy from=/tmp/a to=/tmp/b
Run Code Online (Sandbox Code Playgroud)

你将拥有${from}${to}作为局部变量的函数.

请注意,以下相同的问题适用 - 如果未传递特定变量,则它将从父环境继承.您可能需要添加"安全线",例如:

copy() {
    local from to    # reset first
    local "${@}"

    # ...
}
Run Code Online (Sandbox Code Playgroud)

确保${from}${to}未通过时,将给予取消.


如果您感兴趣的是非常糟糕的事情,您还可以在调用函数时将参数指定为全局变量,即:

from=/tmp/a to=/tmp/b copy
Run Code Online (Sandbox Code Playgroud)

然后你可以在函数中使用${from}和.请注意,您应该始终传递所有参数.否则,随机变量可能会泄漏到函数中.${to}copy()

from= to=/tmp/b copy   # safe
to=/tmp/b copy         # unsafe: ${from} may be declared elsewhere
Run Code Online (Sandbox Code Playgroud)

如果你有bash 4.1(我认为),你也可以尝试使用关联数组.它可以让你通过命名的参数,但它是丑陋的.就像是:

args=( [from]=/tmp/a [to]=/tmp/b )
copy args
Run Code Online (Sandbox Code Playgroud)

然后copy(),你需要抓住阵列.

  • 我真的很喜欢 `local "${@}"` 解决方案的简洁性,规定必须以 name=value 的形式传入命名参数。特别是因为您可以先重置它们,并设置默认值,因为如果它位于函数的开头,它就会成为自记录的。 (2认同)

Wil*_*ell 8

您总是可以在环境中传递信息:

#!/bin/sh
foo() {
  echo arg1 = $arg1
  echo arg2 = $arg2
}

arg1=banana arg2=apple foo
Run Code Online (Sandbox Code Playgroud)


Has*_*own 8

您所要做的就是在进入函数调用的过程中命名变量。

function test() {
    echo $a
}

a='hello world' test
#prove variable didnt leak
echo $a .
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

这不仅仅是函数的一个特性,你可以在它自己的脚本中使用该函数并调用a='hello world' test.sh它,它的工作原理是一样的


作为额外的一点乐趣,您可以将此方法与位置参数结合使用(假设您正在制作一个脚本,而某些用户可能不知道变量名称)。
哎呀,为什么不让它也为这些参数设置默认值呢?好吧,很简单!

function test2() {
    [[ -n "$1" ]] && local a="$1"; [[ -z "$a" ]] && local a='hi'
    [[ -n "$2" ]] && local b="$2"; [[ -z "$b" ]] && local b='bye'
    echo $a $b
}

#see the defaults
test2

#use positional as usual
test2 '' there
#use named parameter
a=well test2
#mix it up
b=one test2 nice

#prove variables didnt leak
echo $a $b .
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

请注意,如果test是它自己的脚本,则不需要使用local关键字。