Basically I need a shell function called echo_Q (or an echo -Q
option), than will echo a quoted argument list, while "[nicely]" strictly avoiding any backslash-quoting on any of the arguments, if possible.
A raw example of the native echo
with some problem arguments:
echo another_script a "b b" "c 'c' c" 'd "d" d' "e "'"'"'e'"'"'" e" "ls -ltrd .??* | sort -k5,5 > f.lst" 'file `ls -t $HOME`' '|' '&' ';' "<"
Naturally, the native echo
produces:
another_script a b b c 'c' c d "d" d e "'e'" e ls -ltrd .??* | sort -k5,5 > f.lst file `ls -t $HOME` | & ; <
In the above result: The quotes have have been evaluated, where necessary spaces and quotes have become opaque.
I've tried, printf " %q" "$@"; echo
, and even:
echo_q(){
sep="";
for arg in "$@"; do
printf "$sep%q" "$arg"
sep=" "
done
echo
}
And get a fully "escaped" (verbose) output, where quoting is totally avoided.
echo_q another_script a "b b" etc..
another_script a b\ b c\ \'c\'\ c d\ \"d\"\ d e\ \"\'e\'\"\ e ls\ -ltrd\ .\?\?\*\ \|\ sort\ -k5\,5\ \>\ f.lst file\ \`ls\ -t\ \$HOME\` \| \& \; \>
In the above result: The output is technically what I want, but kind of "unpleasant" to read due to all the backslashes.
I would prefer (for readability) the output of:
another_script a 'b b' "c 'c' c" 'd "d" d' e\ \"\'e\'\"\ e 'ls -ltrd .??* | sort -k5,5 > f.lst' 'file `ls -t $HOME`' '|' '&' ';' '>'
Here is a "simple" hack I have been dabbling with:
special='$( )*?`<>\\|&;'
qq_special='$`'
echo_Q(){
sep="";
for arg in "$@"; do
printf "$sep";
sep=" "
case "$arg" in
(*["$special'"'"']*)
case "$arg" in
(*'"'*)
case "$arg" in
(*"'"*)printf "%q" "$arg";;
(*)printf "'%s'" "$arg";;
esac;;
(*"'"*)
case "$arg" in
(*"$qq_special"*) printf "%q" "$arg";;
(*) printf '"%s"' "$arg";;
esac;;
(*) printf "'%s'" "$arg";;
esac;;
(*) printf "%s" "$arg";;
esac
sep=" "
done
echo
}
But I'm hoping there is a standard (and simpler) way to "nicely" echo
a function's arguments...
Bash does have: printf "%q"
, but what I need is a printf "%Q"
to nicely quote an argument. Sadly, something so simple eludes me. :-(
Hints welcomed!
Bash does support a way to quote a parameter in a way that can be re-used as an input agin. Parameter expansion ${parameter@operator}
supports a flag (introduced on bash v4.4)
Q The expansion is a string that is the value of parameter quoted in a format that can be reused as input.
set -- a "b b" "c 'c' c" 'd "d" d' "e "'"'"'e'"'"'" e" "ls -ltrd .??* | sort -k5,5 > f.lst" 'file `ls -t $HOME`' '|' '&' ';' "<"
for arg in "$@"; do
printf '%s\n' "${arg@Q}"
done
produces
'a'
'b b'
'c '\''c'\'' c'
'd "d" d'
'e "'\''e'\''" e'
'ls -ltrd .??* | sort -k5,5 > f.lst'
'file `ls -t $HOME`'
'|'
'&'
';'
'<'