Uvozovky jsou odstraněny před předáním argumentů vašemu skriptu, takže je příliš pozdě na jejich zachování. Co můžete udělat, je zachovat jejich účinek při předávání argumentů vnitřnímu příkazu a rekonstruovat ekvivalentní verzi argumentů v uvozovkách/escaped pro tisk.
Pro předání argumentů vnitřnímu příkazu "[email protected]"
-- s dvojitými uvozovkami pří[email protected] zachová původní zalomení slov, což znamená, že vnitřní příkaz obdrží přesně stejný seznam argumentů jako váš skript.
Pro tisk můžete použít formát %q v příkazu printf bash k rekonstrukci citace. Všimněte si, že to nebude vždy rekonstruovat původní citaci, ale vytvoří ekvivalent řetězec v uvozovkách/escaped. Pokud jste například předali argument 'uptime ; uname -a'
může vypsat uptime\ \;\ uname\ -a
nebo "uptime ; uname -a"
nebo jakýkoli jiný ekvivalent (viz odpověď @William Pursell pro podobné příklady).
Zde je příklad použití:
printf "Running command:"
printf " %q" innercmd "[email protected]" # note the space before %q -- this inserts spaces between arguments
printf "\n"
innercmd "[email protected]"
Pokud uživatel zavolá váš příkaz jako:
./script 'foo'
první argument daný skriptu je řetězec foo
bez uvozovek. Neexistuje žádný způsob, jak by váš skript rozlišil mezi tímto a jakoukoli jinou metodou, pomocí které by mohl získat foo
jako argument (např. ./script $(echo foo)
nebo ./script foo
nebo ./script "foo"
nebo ./script \f\o""''""o
).
Pokud chcete vytisknout seznam argumentů co nejblíže tomu, co uživatel pravděpodobně zadal:
#!/bin/bash
chars='[ !"#$&()*,;<>?\^`{|}]'
for arg
do
if [[ $arg == *\'* ]]
then
arg=\""$arg"\"
elif [[ $arg == *$chars* ]]
then
arg="'$arg'"
fi
allargs+=("$arg") # ${allargs[@]} is to be used only for printing
done
printf '%s\n' "${allargs[*]}"
Není to dokonalé. Argument jako ''\''"'
je obtížnější vyhovět, než je oprávněné.