2017-05-16 17:29:13 +0100, Stephane Chazelas:
[...]
> > | Here, I'd fire awk and quote more than one arg at a time:
> >
> > Hmm - you're really aiming for maximum sluggishness... I could beat that
> > by just adding a couple of sleeps ...
>
> Depends. If quoting only a handful a arguments, then that call
> to awk might cost you you a couple of milliseconds indeed. But
> if processing thousands, you might find that it saves a few
> seconds.
Actually, even for a handful of arguments, and even with gawk,
it seems it's generally quicker to use awk in my tests:
With 5 arguments (where "a" uses your quote() and "b" uses mine, see below):
(zsh syntax below)
$ szsh() (exec -a sh zsh "$@")
$ for shell (dash bash mksh szsh ksh93 yash) for file (a b) (TIMEFMT="$shell
$file %*E"; time (repeat 100 $shell ./$file "a'b'c"{1..5}) > /dev/null)
dash a 0.329
dash b 0.407
bash a 0.942
bash b 0.528
mksh a 1.598
mksh b 0.540
szsh a 0.763
szsh b 0.622
ksh93 a 0.667
ksh93 b 0.464
yash a 0.738
yash b 0.429
In mksh, printf is not built-in which doesn't help. In all but
ksh93, that still does 5 forks because of the $(set +o).
dash is the only one that manages to be quicker (not if I use
mawk instead of gawk though).
For 3000 arguments, that's where we see the real advantage of using a real
programming language instead of inadequate features of a shell :-b:
$ for shell (dash bash mksh szsh ksh93 yash) for file (a b) (TIMEFMT="$shell
$file %*E"; time ($shell ./$file "a'b'c"{1..3000}) > /dev/null)
dash a 0.827
dash b 0.019
bash a 7.712
bash b 0.080
mksh a 9.928
mksh b 0.022
szsh a 2.274
szsh b 0.028
ksh93 a 1.184
ksh93 b 0.022
yash a 2.655
yash b 0.035
the scripts under test:
$ cat a
quote() {
case "$1" in
*\'*) ;; # the harder case, we will get to below.
*) printf "'%s'" "$1"; return 0;;
esac
_save_IFS="${IFS}" # if possible just make IFS "local"
_save_OPTS="$(set +o)" # quotes there not really needed.
IFS=\'
set -f
set -- $1
_result_="${1}" # we know at least $1 and $2 exist, as there
shift # was one quote in the input.
for __arg__
do
_result_="${_result_}'\\''${__arg__}"
done
printf "'%s'" "${_result_}"
# now clean up
IFS="${_save_IFS}" #none of this is needed with a good
"local"...
eval "${_save_OPTS}"
unset __arg__ _result_ _save_IFS _save_OPTS
return 0;
}
s=$(
for i do
quote "$i"; printf ' '
done
)
printf '%s\n' "$s"
$ cat b
quote() {
LC_ALL=C awk -v q="'" -v b='\\' '
function quote(s) {
gsub(q, q b q q, s)
return q s q
}
BEGIN {
sep = ""
for (i = 1; i < ARGC; i++) {
printf "%s", sep quote(ARGV[i])
sep = " "
}
if (sep) print ""
}' "$@"
}
s=$(quote "$@")
printf '%s\n' "$s"
--
Stephane