3 ms·
Here's my solution to the problem I pointed out. The basic idea is let the shell do expansion / word splitting on the to-be-deferred command when defer() is ca
by adrianmonk 3y ago
Here's my solution to the problem I pointed out.
The basic idea is let the shell do expansion / word splitting on the to-be-deferred command when defer() is called, then save the words into an array, and avoid doing expansion. This should avoid running into quoting problems in the first place.
#! /bin/bash
defer_run() {
while [ ${#DEFER_OFFSETS[@]} -gt 0 ]
do
# Get / remove last element of offset and length arrays.
offset=${DEFER_OFFSETS[-1]}; unset DEFER_OFFSETS[-1]
len=${DEFER_LENGTHS[-1]}; unset DEFER_LENGTHS[-1]
# Get a slice of the main array corresponding to one deferred
# command's word list. Execute that word list as a command.
"${DEFER_LIST[@]:$offset:$len}"
done
}
defer() {
declare -g -a DEFER_LIST DEFER_OFFSETS DEFER_LENGTHS
trap defer_run EXIT
DEFER_OFFSETS+=( ${#DEFER_LIST[@]} )
DEFER_LENGTHS+=( $# )
DEFER_LIST+=( "$@" )
}
defer echo a b
defer echo "c d"
This prints:
c d
a b
The quoted string "c d" is preserved all the way through as one argument to echo. The non-quoted ones work as expected too.
Note that since bash doesn't have lists of lists, I've stuck all the word-lists of all the deferred commands together into one giant array, and I've saved offsets and length so I can separate them out again.
Since expansion doesn't happen again after you've deferred a command, you can't expand (say) a variable when the deferred command runs. But if you want to do that, define a function and defer it, or just use eval:
defer eval 'echo $myvar'