【发布时间】:2012-07-25 18:35:12
【问题描述】:
在编写 shell 脚本时,我经常发现自己大部分时间(尤其是在调试时)都在处理参数处理。我编写或维护的许多脚本很容易超过 80% 的输入解析和清理。我将其与我的 Python 脚本进行比较,argparse 为我处理大部分繁重的工作,并让我轻松构建复杂的选项结构和清理/字符串解析行为。
因此,我希望能够让 Python 完成这项繁重的工作,然后在我的 shell 脚本中获取这些经过简化和清理的值,而无需再担心用户指定的参数。
举一个具体的例子,我工作的许多 shell 脚本都被定义为以特定顺序接受它们的参数。您可以调用start_server.sh --server myserver --port 80,但start_server.sh --port 80 --server myserver 失败并显示You must specify a server to start. - 它使解析代码更简单,但并不直观。
因此,第一次通过的解决方案可能很简单,例如让 Python 接受参数,对它们进行排序(将它们的参数放在它们旁边)并返回排序后的参数。因此,shell 脚本仍然会进行一些解析和清理,但用户可以输入比 shell 脚本本机接受的更多的任意内容,例如:
# script.sh -o -aR --dir /tmp/test --verbose
#!/bin/bash
args=$(order.py "$@")
# args is set to "-a --dir /tmp/test -o -R --verbose"
# simpler processing now that we can guarantee the order of parameters
这里有一些明显的限制,特别是parse.py 无法区分带有参数的最终选项和索引参数的开头,但这似乎并不可怕。
所以这是我的问题:1) 是否有任何现有的(最好是 Python)实用程序可以通过比 bash 更强大的东西启用 CLI 解析,然后我的 bash 脚本的其余部分可以访问它消毒,或 2) 以前有人这样做过吗?是否有我不知道的问题、陷阱或更好的解决方案?愿意分享您的实现吗?
一个(非常不成熟的)想法:
#!/bin/bash
# Some sort of simple syntax to describe to Python what arguments to accept
opts='
"a", "append", boolean, help="Append to existing file"
"dir", str, help="Directory to run from"
"o", "overwrite", boolean, help="Overwrite duplicates"
"R", "recurse", boolean, help="Recurse into subdirectories"
"v", "verbose", boolean, help="Print additional information"
'
# Takes in CLI arguments and outputs a sanitized structure (JSON?) or fails
p=$(parse.py "Runs complex_function with nice argument parsing" "$opts" "$@")
if [ $? -ne 0 ]; exit 1; fi # while parse outputs usage to stderr
# Takes the sanitized structure and an argument to get
append=$(arg.py "$p" append)
overwrite=$(arg.py "$p" overwrite)
recurse=$(arg.py "$p" recurse)
verbose=$(arg.py "$p" verbose)
cd $(python arg.py "$p" dir)
complex_function $append $overwrite $recurse $verbose
两行代码,以及对预期参数的简明描述,我们将进入实际的脚本行为。也许我疯了,但这似乎方式比我现在必须做的更好。
我在easy CLI argument parsing 上看到过Parsing shell script arguments 和类似这个wiki 页面的内容,但其中许多模式感觉笨重且容易出错,我不喜欢每次编写shell 脚本时都必须重新实现它们,尤其是当 Python、Java 等有这么好的参数处理库时。
【问题讨论】:
-
你试过getopt吗?
-
@tuxuday 你打败了我...... getopt 应该帮助 dimo414
-
我之前使用过 getopt 和 getopts(请参阅问题底部的 wiki 页面链接),但它们仍然有限制 - 引用链接:“getopt 无法处理空参数字符串或嵌入的参数空白。”和“[getopts] 只能处理短选项(-h)而不会欺骗。”我意识到 bash 中有可用的解决方案,但恕我直言,Python 可用的选项更优越,更容易争论。我很好奇 Python 实用程序的可行性/存在来实现这一点。 “你很笨,使用 bash。”最终可能是这个问题的可接受答案。
-
@dimo414,我们使用
getopt并对此感到满意。检查getopt是否满足您的要求,如果没有,则放弃它。来自我的 expgetopt命令足以满足大多数需求。 -
谢谢,是的,我也使用过getopt。就像我说的,我对此并不满意。它确实有效,但我认为存在或可以制造更好的工具。我正在尝试探索这个想法的可行性,而不是重复 getopt 是解析命令行参数的一种选择。
标签: python bash command-line-arguments