I have a Bash function library and one function is proving problematic for testing. prunner
is a function that is meant to provide some of the functionality of GNU Parallel, and avoid the scoping issues of trying to use other Bash functions in Perl. It supports setting a command to run against the list of arguments with -c
, and setting the number of background jobs to run concurrently with -t
.
In testing it, I have ended up with the following scenario:
prunner -c "gzip -fk" *.out
- works as expected in test.bash
and interactively.find . -maxdepth 1 -name "*.out" | prunner -c echo -t 6
- does not work, seemingly ignoring -c echo
.Testing was performed on Ubuntu 16.04 with Bash 4.3 and on Mac OS X with Bash 4.4.
What appears to be happening with the latter in test.bash
is that getopts
is refusing to process -c
, and thus prunner
will try to directly execute the argument without the prefix command it was given. The strange part is that I am able to observe it accepting the -t
option, so getopts
is at least partially working. Bash debugging with set -x
has not been able to shed any light on why this is happening for me.
Here is the function in question, lightly modified to use echo
instead of log
and quit
so that it can be used separately from the rest of my library:
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."
}
Can anyone please help me to determine why -c
options are not working correctly for prunner
when lines are piped to stdin?
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.