我在我的脚本中使用docopts来解析帮助消息中的args。
recommended usage是使用eval来运行命令。我认为这是因为docopts将解析的args设置为可供调用脚本使用的变量。
简化示例:
#!/usr/bin/env bash
function parse() {
eval "$(docopts -h "Usage: your_program <arg> [--verbose]" : "$@")"
}
# Parse some args
parse "some arg" --verbose
# Verify that the variable $arg was correctly set by docopts
if [ -z "${arg+x}" ]; then
echo "\$arg is not set!"
else
echo "the value of \$arg is \"$arg"\"
fi
输出: the value of $arg is "some arg"
当传递的参数无效时,会向stderr打印一条用法消息,退出代码设置为64.我需要将此用法消息捕获到变量中,以便我可以进一步处理它。
在子shell中运行并捕获stderr就是这样:
#!/usr/bin/env bash
function parse() {
usage_error_msg=$(eval "$(./docopts -h "Usage: your_program <arg> [--verbose]" : "$@")" 2>&1)
exit_code=$?
# Exit the program with an error if the usage isn't valid
(( exit_code == 0 )) || { echo "$usage_error_msg"; exit $exit_code; }
}
# Parse some args
parse "some arg" --verbose
# Verify that the variable $arg was correctly set by docopts
if [ -z "${arg+x}" ]; then
echo "\$arg is not set!"
else
echo "the value of \$arg is \"$arg"\"
fi
如果我省略了一个必需的参数(函数的最后一行),这就正确地捕获了输出和exit_code,并使用一条用法消息退出脚本。
但是,脚本中不再提供变量;
输出: $arg is not set!
如何在我的脚本中仍然拥有docopts集可用的变量的同时捕获变量中的stdout?关于将输出捕获到变量的SO的答案似乎总是涉及子shell。
注意:我将docopts作为一个库包含在内,所以我也开放了涉及修改docopts Python脚本的解决方案,虽然我更喜欢纯粹的bash解决方案(我对Python知之甚少并且不想复制将来的docopts依赖关系变得复杂。)
在尝试glenn jackman的答案后,我发现docopts打印到stdout应该执行什么样的eval;
如果语法有效:
verbose=true
arg='some arg'
如果语法无效:
echo 'Usage: your_program <arg> [--verbose]' >&2
exit 64
除非docopts命令本身的语法不正确,否则Docop将始终以0退出。否则,在执行eval之前,不会设置非零退出代码。我想所有依赖这个原理的程序都是这样的。
我应该澄清的原始问题的问题部分中缺少的另一个问题是,当eval执行将带有无效语法的args传递给docopts时产生的输出时,程序退出。因此,当eval运行第二个示例中的代码时,整个脚本将退出。
答案 0 :(得分:1)
尝试延迟eval,直到您知道自己取得了成功:
function parse() {
output=$(./docopts -h "Usage: your_program <arg> [--verbose]" : "$@" 2>&1)
exit_code=$?
# Exit the program with an error if the usage isn't valid
(( exit_code == 0 )) || { echo "$output"; exit $exit_code; }
eval "$output"
}
或者,结构略有不同
function parse() {
if output=$(./docopts -h "Usage: your_program <arg> [--verbose]" : "$@" 2>&1)
then
eval "$output"
else
exit_code=$?
echo "$output"
exit $exit_code
fi
}