2 个版本

0.1.1 2024 年 4 月 11 日
0.1.0 2024 年 4 月 11 日

命令行工具 中排名 391

Download history 4/week @ 2024-05-20 2/week @ 2024-06-10 12/week @ 2024-07-01 95/week @ 2024-07-29

每月下载量 95

MIT 许可证

63KB
1K SLoC

ArgParse-sh

用于解析 shell 脚本参数并提供结果作为环境变量的工具。

安装

Cargo 安装

首选的安装方法使用 cargo,Rust 工具。如果您在本地机器上安装了 Rust,请运行

cargo install argparse-sh

二进制文件将被构建并放入您的 ~/.cargo/bin/ 文件夹中。将其添加到您的 PATH 或直接引用,您就设置好了。

从源代码构建

您可以从源代码下载和构建应用程序。这同样需要您在本地机器上安装 Rust 以及 Git。要这样做,请运行

git clone [email protected]:Hounshell/argparse-sh.git
cd argparse-sh
cargo build --release

编译后的二进制文件将在 target/release/argparse-sh。将此文件放在您喜欢的位置,并将其添加到您的 PATH 或直接引用。

使用方法

ArgParse-sh 接受两组参数。第一组定义所有要解析的参数。第二组是要解析的参数。这最好通过一个简单的示例来说明

$ argparse-sh --string text -- --text "Hello, world!"
TEXT="Hello, world!"

这做了什么?它定义了一组参数(一个名为 "text" 的字符串参数)然后解析了一组参数值。输出是一个设置提供参数的环境变量的脚本。

这是一个简单的示例,但不是很实用。相反,让我们将其放入一个脚本中,并通过脚本将参数传递给 ArgParse-sh

demo.sh

eval "$(argparse-sh --string text -- "$@")";
echo "$TEXT"

让我们把这个脚本拆分成几个部分

  • argparse-sh - 这将调用 ArgParse-sh 程序

  • --string text - 这表示 ArgParse-sh 可以接受一个名为 "text" 的可选参数。值是字符串,没有默认值。

  • -- - 这表示 ArgParse-sh 我们已经完成了参数的定义。所有剩余的命令行参数都应该被视为参数值。

  • "$@" - 将脚本调用时传递的所有参数转发到ArgParse-sh。因为这在--之后,ArgParse-sh将解释这些参数。

  • eval "$(...)"; - ArgParse-sh的输出是脚本命令。eval在当前shell中执行这些命令。

  • echo "$TEXT" - ArgParse-sh将输出的脚本命令设置环境变量为参数的值。这将打印传递给"text"参数的值。

如果我们运行demo.sh,我们可以看到这一切都在行动中。

$ ./demo.sh --text "Hello, world!"
Hello, world!

ArgParse-sh识别--text参数并期望一个字符串。这个字符串("Hello, world!")被写入名为"TEXT"的环境变量中(根据参数的名称),然后可以被脚本的其他部分使用。

在下面的几个示例中,我们将省略argparse-sh命令中的eval部分。这将导致ArgParse-sh的输出直接显示在屏幕上,让我们更清楚地看到发生了什么。

参数类型

支持几种参数类型。通常它们共享相同的一组选项(当这样做有意义时),并且一些具有额外的选项或形式。

常见参数参数

定义参数有一个常见的模式,以及一些可以提供的常见参数。

--<type> [<name / key 1> <key 2> <key 3> ...]

要开始定义一个参数,我们需要指定参数类型。在类型之后,我们可以提供用于提供此参数的名称和键的缩写。这个缩写涵盖了最常见的案例,但您不必使用它;名称和标志可以单独定义。

可用的类型有

  • --boolean--bool - "true"或"false"值。
  • --choice--pick - 从选项列表中选择一个。
  • --float--number - 64位浮点数。
  • --integer--int - 64位有符号整数。
  • --string--str - 自由文本。
示例
$ argparse-sh --string given-name first-name name -- --first-name "Alice"
GIVEN_NAME="Alice"

这创建了一个名为"GIVEN_NAME"的单个字符串参数,可以使用--given-name--first-name--name设置。这是缩写形式

$ argparse-sh --string --name GIVEN_NAME \
    --flag "--given-name" \
    --flag "--first-name" \
    --flag "--name" \
    -- --first-name "Alice"
GIVEN_NAME="Alice"

--name <name>

提供要存储此参数值的环境变量的名称。

如果没有提供名称,则将使用定义的第一个标志(使用--flag或上述缩写)。规范化删除任何前导或尾随的非字母数字字符。所有其他非字母数字序列都将替换为"_",整个字符串将大写。例如,如果第一个标志是"--first-name",则规范化的名称将是"FIRST_NAME"。

示例
$ argparse-sh --string name --name FIRST_NAME -- --name "Alice"
FIRST_NAME="Alice"

这将配置一个字符串参数,可以使用--name "Name"设置,但将存储在FIRST_NAME环境变量中。

--flag <flag>

提供一个标志,可用于指定此参数的值。该标志将原样使用,包括大小写和连字符。这是支持较短标志的好方法。您可以在没有连字符的情况下指定标志名称。

示例
$ argparse-sh --string name --flag "--first-name" --flag "-n" -- -n Alice
NAME="Alice"

这使用简写方法定义了一个名为 "NAME" 的字符串参数,但同时也定义了可用的替代标志("--first-name" 和 "-n")。

--default <默认值>

提供在未指定此参数时使用的默认值。

警告:此默认值不会被解析或验证;无效的值将被传递。

示例
$ argparse-sh --string name --default "Alice"
NAME="Alice"

如果提供了 -- --name "Bob",则 NAME 将设置为 "Bob",而不是 "Alice"。

--desc[ription] <描述>

提供用于在生成帮助文本时使用此参数的描述。

示例
$ eval "$(argparse-sh --string name --desc "The user's first name." --autohelp -- --help)"

OPTIONS
       --name <name>
           The user's first name.

我们在这个例子中使用了 eval,因为否则很难看到输出。已为所有参数生成了帮助文本(在这种情况下仅指定了 --name),并将帮助文本用于该参数的描述中。

--repeated

表示此参数可以重复。如果重复参数,则环境变量将设置为存在的值的数量,并且每个值都将设置为其自己的环境变量,带有基于0的索引后缀。

示例
$ argparse-sh --string name --repeated -- --name "Alice" --name "Bob" --name "Carol"
NAME="3"
NAME_0="Alice"
NAME_1="Bob"
NAME_2="Carol"

在这里,我们可以看到提供了三个名字。每个 --name 的值按顺序包含。

--required

表示此参数是必需的。如果没有提供,ArgParse-sh 将失败。

示例
$ argparse-sh --string name --required
echo ""
echo "!!! ArgParse-sh Error: Value for argument NAME is missing !!!"
echo ""

$ echo $?
2

显示错误消息,指出未提供 "name" 参数。当解析参数时出现错误时,ArgParse-sh 的退出代码为 2。

--secret

将参数标记为不在生成的帮助文本中包含。

示例
$ eval "$(target/debug/argparse-sh --string name --secret --string age --autohelp -- --help)"

OPTIONS
       --age <age>
           No details available.

我们再次使用 eval 以提高清晰度。请注意,为 "age" 参数生成了帮助文本,但没有为 "name" 参数生成。

--catch-all

用于标记将获取任何未识别值的参数。这对于不需要用户指定标志名称的重复参数特别有用。

请注意,捕获所有参数不需要任何标志,但建议您仍然为用户提供一些标志,以便他们可以使用 --flag=value 语法。如果不使用任何标志,则参数 必须 有一个名称。

示例
$ argparse-sh --string name --catch-all -- "Bob"
NAME="Bob"

--ordinal <顺序>

使此参数表现得像捕获所有参数,但它只会接受单个值,并且只有当没有明确提供值时。order 是一个整数,它提供了序数参数的填充顺序。下一个没有值的最低参数(例如,用户没有通过标志明确提供此参数的值)将被使用。这意味着序数可以开始于您喜欢的任何数字,并且可以在数字之间有间隔。

示例
$ argparse-sh \
    --string first_name --ordinal 1 --required \
    --string middle_name --ordinal 2 --required \
    --string last_name --ordinal 3 --required \
    -- --middle_name "Quincy" "Alice" "Smith"
FIRST_NAME="Alice"
MIDDLE_NAME="Qunicy"
LAST_NAME="Smith"

字符串参数 (--string 或 --str)

字符串参数不会对其值进行任何验证或重写。这些参数简单地传递到环境变量中。字符串参数支持所有常见的参数参数。

示例

$ argparse-sh \
    --string first-name --required \
    --string last-name --default "Doe" \
    --string nickname --repeated --catch-all \
    -- \
    --first-name "John" \
    --nickname "Sticky Fingers" \
    --nickname "Tight Lips"
FIRST_NAME="John"
LAST_NAME="Doe"
NICKNAME="2"
NICKNAME_0="Sticky Fingers"
NICKNAME_1="Tight Lips"

整数参数 (--integer 或 --int)

整数参数会进行验证。提供的值必须可以解析为 64 位有符号整数。如果提供了无效的参数,则 argparse-sh 将失败,并显示一条消息和一个错误代码为 2。整数参数支持所有常见的参数参数。

重要:如果提供了默认值,则不会进行验证。您负责确保提供的值解析为整数,或者您的脚本能够处理非整数值。

示例

$ argparse-sh \
    --integer age --required \
    --integer children --default 0 \
    --integer pockets --required --catch-all \
    -- \
    --age 42 \
    7
AGE="42"
CHILDREN="0"
POCKETS="7"

浮点参数 (--float 或 --number)

浮点参数也会进行验证。提供的值必须可以解析为64位浮点数。如果提供了无效的参数,argparse-sh 将会失败并显示错误消息,错误代码为2。浮点参数支持所有常见的参数。

重要:如果提供了默认值,则不会进行验证。您负责确保提供的值解析为数字,或者您的脚本能够处理非数字值。

示例

$ argparse-sh \
    --float height --required \
    --float weight --default 0 \
    --float cash-on-hand --catch-all \
    -- \
    --height 180.4 \
    72.34
HEIGHT="180.4"
WEIGHT="0"
CASH_ON_HAND="72.34"

选择参数 (--choice 或 --pick)

选择参数与其他参数类型略有不同,但与字符串参数最为相似。使用选择参数时,您提供一组有效的选择和备用映射。如果提供了未识别的值,argparse-sh 将会失败并显示错误消息,错误代码为2。

重要:如果提供了默认值,则不会进行验证,也不会进行映射。您负责确保提供的值解析为您的选择之一,或者您的脚本能够处理此值。

--option <name> [<help_text>]

选择参数需要一个或多个选项参数。在 --option 之后,您必须包含选项名称。您还可以提供显示在该选项之后的帮助文本。

--map <from> <to>

将一个选项映射到另一个选项。这为具有多个名称的特定选项提供了一个简单的方法。

重要:您可以映射到不存在的选项。您负责确保映射到的选项存在。映射不是链式的;如果从 "a" 映射到 "b",从 "b" 映射到 "c",并且用户提供了 "a",则值将是 "b"。

示例

$ argparse-sh \
    --choice gender --default "none" \
        --option male "Person identifies as male" \
        --option female "Person identifies as female" \
        --map boy male \
        --map girl female \
        --option other "Person identifies as something else" \
        --option none "Person declines to identify" \
    -- \
    --gender boy
GENDER="male"

$ eval "$(argparse-sh \
    --choice gender --default "none" \
        --option male "Person identifies as male" \
        --option female "Person identifies as female" \
        --map boy male \
        --map girl female \
        --option other "Person identifies as something else" \
        --option none "Person declines to identify" \
    --autohelp \
    -- \
    --help)"

OPTIONS
       --gender <gender>
           No details available.

           The possible options are:

              male - Person identifies as male

              female - Person identifies as female

              boy - Identical to 'male'

              girl - Identical to 'female'

              other - Person identifies as something else

              none - Person declines to identify

           When this option is not provided it will default to 'none'.

布尔参数 (--boolean 或 --bool)

布尔参数,与选择参数一样,具有额外的行为。

默认情况下,布尔参数没有值。如果用户没有指定该参数,则变量不会被设置。如果用户使用 --flag-name 提供了标志,则布尔参数的值将是 "true"。但是,用户也可以通过使用 --flag-name=false 明确指定值。用户输入仅接受 "true" 和 "false"。您可以使用 --default 标志确保它始终设置。

布尔参数不能重复,不能有顺序,也不能用作通配符。如果您尝试使用这些特性定义一个布尔参数,您将得到定义错误。

示例
$ argparse-sh --boolean happy -- --happy
HAPPY="true"

--negative-flag <flag>

布尔参数允许定义负标志。这些标志强制将值设置为 "false"。否定标志是明确定义的。

示例

$ argparse-sh --boolean happy --negative-flag "--not-happy" -- --not-happy
HAPPY="false"

这种技术与 --default 参数或 --required 参数结合使用特别有用。

$ argparse-sh --boolean happy --negative-flag "--sad" --required -- --sad
HAPPY="false"

$ argparse-sh --boolean --name "HAPPY" --negative-flag "--sad" --default "true" --
HAPPY="true"

第一行要求您包含 --happy--sad 之一。如果您两者都不包含,您将得到用户错误。如果您两者都包含,您将因为 "HAPPY" 有多个值而得到错误。

第二行将 "HAPPY" 定义为默认值为 "true" 的布尔值,但可以通过包含 --sad 参数将其设置为 "false"。

其他运行时选项

在运行 argparse-sh 时,还有一些其他选项可以使用。这些选项可以放在参数列表的任何位置,但建议您将它们放在参数列表的开始或结尾。它们不能放在参数定义内部(例如,argparse-sh --bool --debug --name bad-example 是不允许的)。

--debug

通过 echo 输出调试信息。当试图确定为什么一个参数没有按预期的方式表现时,这很有用。

示例

$ eval "$(argparse-sh \
    --choice gender --default "none" \
        --option male "Person identifies as male" \
        --option female "Person identifies as female" \
        --map boy male \
        --map girl female \
        --option other "Person identifies as something else" \
        --option none "Person declines to identify" \
    --debug \
    -- \
    --gender boy)"
[ArgParse-sh] ArgParse-sh debugging enabled with --debug flag
[ArgParse-sh] Arguments are not exported to child processes
[ArgParse-sh] 
[ArgParse-sh] Definition - type: Choice; name: GENDER; flags: gender; default: none; options: male, female, boy -> male, girl -> female, other, none
[ArgParse-sh] 
[ArgParse-sh] Parsing argument values
[ArgParse-sh] 
[ArgParse-sh] Parsed argument GENDER = 'male'
[ArgParse-sh] 
[ArgParse-sh] Setting GENDER = "male"
[ArgParse-sh] 
[ArgParse-sh] ArgParse-sh completed successfully

--auto-help

--export

--prefix <arg_prefix>

--program-name <name>

--program-summary <summary>

--program-description <description>

退出代码

  • 0 - 成功

    当 ArgParse-sh 成功完成时,退出代码将为 0。如果发生这种情况,您可以确信所有必需的参数都已设置,所有提供的参数都已解析,并且所有类型检查都已成功完成。

  • 1 - 帮助

    如果使用了 --autohelp 标志并且用户传递了 --help,则帮助文本将写入屏幕(如果设置了用户的 PAGER,则使用用户的 PAGER)并且 ArgParse-sh 将以代码 1 退出。

  • 2 - 定义错误

    如果参数定义存在问题,则退出代码将为 2。例如,在 --name 后没有包括参数名称将生成此错误。

  • 3 - 用户错误

    如果用户提供的参数存在问题,则返回此错误代码。例如,标记为必需的省略参数或为非重复参数提供多个值。

如果您在调用 argparse-sh 之前运行 set -,则如果 ArgParse-sh 返回的退出代码不是 0,则您的脚本将自动退出。您还可以捕获此错误以更优雅地恢复。

综合起来。

这是一个使用广泛功能和最佳实践的脚本示例。

demo.sh

# Set shell to exit immediately after failed command.
set -e;

# The description is long, so we pulled it out into a variable for clarity.
PROGRAM_DESCRIPTION="This demo program provides a number of examples of how to use ArgParse-sh.
You can provide a number of arguments that are parsed and sent back to the wrapper script as
environment variables.

Feel free to save this script and run it with a variety of parameters to test things out.";

# Run ArgParse-sh with argument definitions and pass command line through.
eval "$(argparse-sh \
  --string given-name first-name \
      --description "Name given to you. In western cultures this is usually your first name." \
      --required \
  --string family-name last-name \
      --description "Name inherited from your family. In western cultures this is usually your last name." \
      --required \
  --string nickname \
      --name NICKNAMES \
      --description "Nicknames that you are commonly known by." \
      --repeated \
  --integer age \
      --description "Your age in years." \
      --required \
  --integer children \
      --default 0 \
      --secret \
  --choice gender \
      --description "The gender that you identify as." \
      --option male "Person identifies as male" \
      --map boy male \
      --option female "Person identifies as female" \
      --map girl female \
      --option other "Person identifies as something else" \
      --option none "Person declines to identify" \
      --default none \
  --boolean basic-data one-line single-line \
      --description "Include this argument if you only want to see the first line in the output." \
  --string quote \
      --name QUOTES \
      --description "Include one or more quotes that you find inspirational." \
      --repeated \
      --required \
      --catch-all \
  --auto-help \
  --prefix "DEMO_" \
  --program-name "$(basename "$0")" \
  --program-summary "Sample script that uses argparse-sh to parse command line arguments." \
  --program-description "$PROGRAM_DESCRIPTION" \
  -- "$@")";

# Dump some of the basic variables to the screen.
echo "Hello $DEMO_GIVEN_NAME. I see you are $DEMO_AGE years old and have $DEMO_CHILDREN children.";

# We can test for existence of boolean variables
if [ "$DEMO_BASIC_DATA" = "true" ]; then
  exit
fi

# We can use if statements to switch logic based on the results of a flag.
if [ "$DEMO_GENDER" = "male" ]; then
  echo "You identify as male."
elif [ "$DEMO_GENDER" = "female" ]; then
  echo "You identify as female."
elif [ "$DEMO_GENDER" = "other" ]; then
  echo "You identify as something other than strictly male or female."
else 
  echo "You have declined to provide your gender identity."
fi

# We can test to see if variables are set, even for repeated arguments.
if [ -n "$DEMO_NICKNAMES" ]; then
  echo ""
  echo "You have $DEMO_NICKNAMES nickname(s):";
  for (( i=0; i<$DEMO_NICKNAMES; i++ )); do
    # We need to do this expansion to iterate over all of the values in the list.
    NICKNAME=DEMO_NICKNAMES_$i
    echo "  ${!NICKNAME}";
  done
fi

# If an argument is required you can be guaranteed that the value is set, even for repeated args.
echo ""
echo "You have $DEMO_QUOTES favorite quote(s):";
for (( i=0; i<$DEMO_QUOTES; i++ )); do
  QUOTE=DEMO_QUOTES_$i
  echo "  ${!QUOTE}";
done

您可以使用 --help 运行此脚本以获取帮助文本

依赖关系

~2.7–4MB
~59K SLoC