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