将命令行参数分成两个列表并传递给程序 (shell)

Separate command-line arguments into two lists and pass to programs (shell)

我想要做的是获取类似命令的参数列表,如 abc "def ghi" "foo bar" baz(请注意,一些参数被引用是因为它们包含空格),并将它们分成两个参数列表,然后得到传递给脚本调用的其他程序。例如,一个程序的奇数参数和另一个程序的偶数参数。保持正确的引用很重要。

请注意,我需要一个纯 Bourne Shell 脚本的解决方案(即 sh 而不是 bash 等)。我在 Bash 中这样做的方法是使用数组,但 Bourne Shell 当然不支持数组。

这可能是您所需要的。 las,它使用eval。 YMMV.

#!/bin/sh

# Samples
foo() { showme foo "$@"; }
bar() { showme bar "$@"; }
showme() {
        echo " args:"
        shift
        local c=0
        while [ $# -gt 0 ]; do
                printf '\t%-3d %s\n' $((c=c+1)) ""
                shift
        done
}

while [ $# -gt 0 ]; do
        foo="$foo \"\""
        bar="$bar \"\""
        shift 2
done

eval foo $foo
eval bar $bar

这里没有魔法——我们只是将带有引号装甲的交替参数编码到变量中,这样当您 eval 该行时它们就会被正确处理。

我用基于 ash 的 FreeBSD /bin/sh 测试了这个。 shell 接近于 POSIX.1 但不一定是 "Bourne"。如果您的 shell 不接受 shift 的参数,您可以在 while 循环中简单地移动两次。类似地,showme() 函数递增一个计数器,如果我的方法不适合您,可以通过您喜欢的任何方式实现该操作。我相信其他一切都很标准。

以对原始参数进行两次迭代为代价,您可以定义一个函数,该函数可以 运行 仅使用偶数或奇数参数的 简单 命令。这允许我们将函数的参数用作附加数组。

# Usage:
#  run_it <cmd> [even|odd] ...
# 
#  Runs <cmd> using only the even or odd arguments, as specified.
run_it () {
    cmd=${1:?Missing command name}
    parity=${2:?Missing parity}
    shift 2

    n=$#

    # Collect the odd arguments by discarding the first
    # one, turning the odd arguments into the even arguments.
    if [ $# -ge 1 ] && [ $parity = odd ]; then
        shift
        n=$((n - 1))
    fi

    # Repeatedly move the first argument to the
    # to the end of the list and discard the second argument.
    # Keep going until you have moved or discarded each argument.
    while [ "$n" -gt 0 ]; do
        x=
        if [ $n -ge 2 ]; then
            shift 2
        else
            shift
        fi
        set -- "$@" "$x"
        n=$((n-2))
    done

    # Run the given command with the arguments that are left.
    "$cmd" "$@"
}

# Example command
cmd () {
    printf '%s\n' "$@"
}

# Example of using run_it
run_it cmd even "$@"
run_it cmd odd "$@"