【问题标题】:how to make a generic Bash function that can accept information via positional and named arguments如何制作一个可以通过位置和命名参数接受信息的通用 Bash 函数
【发布时间】:2025-11-23 00:25:02
【问题描述】:

我正在编写大量的 Bash 函数,这些函数能够从使用位置参数命名参数(由getopts 提供)传递的命令行获取不同的信息。这个想法是位置参数主要用于快速和直接的人工控制,而命名参数主要用于其他功能的清晰度和控制。为了说明我是如何考虑这个问题的,考虑一个可以从一个事物转换为另一个事物的函数。从广义上讲,可以在快速模式或高级模式中使用此功能。在快速模式中,指定的参数很少,通常是位置参数,而在高级模式中,可以指定许多参数,通常是命名参数。比如……

快速模式

可以通过以下方式使用此模式:

function fileName1 fileName2

它使用内部假设和自主进行的测量将一个文件转换为另一个文件。

高级模式

可以通过以下方式使用此模式:

function -i fileName1 -o fileName2 -m -r 100 -v

此模式也可以通过以下方式使用:

function -m -v fileName1 fileName2 -r 100

请注意,-v 不接受任何参数。它只是一个选项(指定诸如详细程度之类的内容)。


因此,这种情况下的逻辑是第一个 positional 参数假定为fileName1,第二个位置参数假定为fileName2 除非 使用-i-o 选项指定这些文件名中的任何一个,在这种情况下使用它们,因为它们被赋予了更高的优先级(并且忽略了第一个和第二个位置参数)。

我在以尽可能通用的方式实现这些类型的要求时寻求建议和指导,因为这种方法将应用于包含 150 多个函数的库。

【问题讨论】:

标签: bash arguments options getopt getopts


【解决方案1】:

请注意,如果您使用getoptsall positional arguments must come after any options。第二个警告是,如果您使用 getopts 解析函数的参数,您必须在解析任何选项后将全局 OPTIND 变量重置为 1。否则我认为解决方案很简单:

argparse.sh

#!/usr/bin/env bash

func() {
    local args=$*
    local input output verbose
    local r="unset" m=0 verbose=0

    while getopts i:o:mr:v opt; do
        case "$opt" in
            i) input="$OPTARG" ;;
            o) output="$OPTARG" ;;
            r) r="$OPTARG" ;;
            m) m=1 ;;
            v) verbose=1 ;;
        esac
    done
    shift $((OPTIND-1))
    OPTIND=1    # reset global variable

    [[ $input ]]  || input=$1
    [[ $output ]] || output=$2

    echo "=== func $args ==="
    echo "input: $input"
    echo "output: $output"
    echo "verbose: $verbose"
    echo "r: $r"
    echo "m: $m"
    echo
}

func fileName1 fileName2
func -i fileName1 -o fileName2 -m -r 100 -v
func -m -v -r 100 fileName1 fileName2

输出

=== func fileName1 fileName2 ===
input: fileName1
output: fileName2
verbose: 0
r: unset
m: 0

=== func -i fileName1 -o fileName2 -m -r 100 -v ===
input: fileName1
output: fileName2
verbose: 1
r: 100
m: 1

=== func -m -v -r 100 fileName1 fileName2 ===
input: fileName1
output: fileName2
verbose: 1
r: 100
m: 1

【讨论】:

  • 非常感谢您的建议和高效的代码。我之前没有看到没有if 语句的方括号测试,但我明白它是如何有意义的。我正在尝试做的是有效地允许使用其指定的选项字符串解释 getopts 不可接受的参数。然后,我想解决使用优先级规则引起的冲突。也许my most recent question 可以稍微澄清一下。
【解决方案2】:

我使用@getopt@ 来解析命令行参数。我现在不记得它是否能解决你的问题。但这对我很有用。

http://linux.die.net/man/1/getopt

【讨论】:

  • 感谢您的建议。我不知道getopt 可以通过何种方式返回它尚未接受的参数。
【解决方案3】:

改编自http://rsalveti.wordpress.com/2007/04/03/bash-parsing-arguments-with-getopts/

总是先尝试 getopts 怎么样,如果失败则恢复为仅使用 $1/$2/etc。

TEST=
SERVER=
PASSWD=
VERBOSE=
while getopts “ht:r:p:v” OPTION
do
     case $OPTION in
         h)
             usage
             exit 1
             ;;
         t)
             TEST=$OPTARG
             ;;
         r)
             SERVER=$OPTARG
             ;;
         p)
             PASSWD=$OPTARG
             ;;
         v)
             VERBOSE=1
             ;;
         ?)
             usage
             exit
             ;;
     esac
done

if [[ -z $TEST ]] || [[ -z $SERVER ]] || [[ -z $PASSWD ]]
then
     // Set variables from $1/$2/etc....
fi

【讨论】:

  • 非常感谢您的建议。你的建议确实有一种明确的意义,但我想做的是允许解释 getopts 不能接受的参数及其指定的选项字符串 - 不丢弃成功的 getopts 解析。然后,我想解决使用优先级规则引起的冲突。也许my most recent question 可以稍微澄清一下。
最近更新 更多