源代码Bash函数中的Getopts以交互方式工作,但不在测试脚本中工作?

时间:2018-03-22 23:20:06

标签: bash shell getopts

我有一个Bash函数library,并且一个函数证明在测试时存在问题。 prunner是一个函数,旨在提供GNU Parallel的一些功能,并避免尝试在Perl中使用其他Bash函数的范围问题。它支持将命令设置为针对-c的参数列表运行,并设置后台作业的数量与-t同时运行。

在测试中,我最终得到了以下场景:

  • prunner -c "gzip -fk" *.out - 按预期在test.bash和交互式工作。
  • find . -maxdepth 1 -name "*.out" | prunner -c echo -t 6 - 无效,似乎无视-c echo

测试是在Ubuntu 16.04上使用Bash 4.3进行的,在Mac OS X上使用Bash 4.4进行。

后者在test.bash中似乎发生的事情是getopts拒绝处理-c,因此prunner将尝试直接执行参数而不是-t它给出了前缀命令。奇怪的是,我能够观察它接受getopts选项,因此set -x至少部分有效。使用echo进行Bash调试无法解释为什么会发生这种情况。

以下是相关功能,经过轻微修改后使用log代替quit prunner () { local PQUEUE=() while getopts ":c:t:" OPT ; do case ${OPT} in c) local PCMD="${OPTARG}" ;; t) local THREADS="${OPTARG}" ;; :) echo "ERROR: Option '-${OPTARG}' requires an argument." ;; *) echo "ERROR: Option '-${OPTARG}' is not defined." ;; esac done shift $(($OPTIND-1)) for ARG in "$@" ; do PQUEUE+=("$ARG") done if [ ! -t 0 ] ; then while read -r LINE ; do PQUEUE+=("$LINE") done fi local QCOUNT="${#PQUEUE[@]}" local INDEX=0 echo "Starting parallel execution of $QCOUNT jobs with ${THREADS:-8} threads using command prefix '$PCMD'." until [ ${#PQUEUE[@]} == 0 ] ; do if [ "$(jobs -rp | wc -l)" -lt "${THREADS:-8}" ] ; then echo "Starting command in parallel ($(($INDEX+1))/$QCOUNT): ${PCMD} ${PQUEUE[$INDEX]}" eval "${PCMD} ${PQUEUE[$INDEX]}" || true & unset PQUEUE[$INDEX] ((INDEX++)) || true fi done wait echo "Parallel execution finished for $QCOUNT jobs." } ,以便可以与我的其他库分开使用:

-c

任何人都可以帮助我确定为什么prunner选项在使用管道输送到标准输入时[ { id: 10 name : abc }, { id: 11 name : xyz } ] 无法正常工作?

2 个答案:

答案 0 :(得分:4)

My guess is that you are executing the two commands in the same shell. In that case, in the second invocation, OPTIND will have the value 3 (which is where it got to on the first invocation) and that is where getopts will start scanning.

If you use getopts to parse arguments to a function (as opposed to a script), declare local OPTIND=1 to avoid invocations from interfering with each other.

答案 1 :(得分:0)

Perhaps you are already doing this, but make sure to pass the top-level shell parameters to your function. The function will receive the parameters via the call, for example:

xyz () {
    echo "First arg: ${1}"
    echo "Second arg: ${2}"
}
xyz "This is" "very simple"

In your example, you should always be calling the function with the standard args so that they can be processed in the method via getopts.

prunner "$@"

Note that pruner will not modify the standard args outside of the function.