Usa eval:
x="ls | wc"
eval "$x"
y=$(eval "$x")
echo "$y"
No usa eval
! Ha un grosso rischio di introdurre l'esecuzione di codice arbitrario.
BashFAQ-50 - Sto cercando di inserire un comando in una variabile, ma i casi complessi falliscono sempre.
Mettilo in un array ed espandi tutte le parole con le virgolette "${arr[@]}"
non lascia che il IFS
dividere le parole a causa della suddivisione delle parole.
cmdArgs=()
cmdArgs=('date' '+%H:%M:%S')
e vedere il contenuto dell'array all'interno. Il declare -p
ti permette di vedere il contenuto dell'array all'interno con ogni parametro di comando in indici separati. Se uno di questi argomenti contiene spazi, le virgolette all'interno durante l'aggiunta all'array eviteranno che venga diviso a causa della divisione delle parole.
declare -p cmdArgs
declare -a cmdArgs='([0]="date" [1]="+%H:%M:%S")'
ed eseguire i comandi come
"${cmdArgs[@]}"
23:15:18
(o) utilizzare del tutto un bash
funzione per eseguire il comando,
cmd() {
date '+%H:%M:%S'
}
e chiama la funzione come just
cmd
POSIX sh
non ha array, quindi il massimo che puoi fare è creare un elenco di elementi nei parametri posizionali. Ecco un POSIX sh
modo per eseguire un programma di posta
# POSIX sh
# Usage: sendto subject address [address ...]
sendto() {
subject=$1
shift
first=1
for addr; do
if [ "$first" = 1 ]; then set --; first=0; fi
set -- "[email protected]" --recipient="$addr"
done
if [ "$first" = 1 ]; then
echo "usage: sendto subject address [address ...]"
return 1
fi
MailTool --subject="$subject" "[email protected]"
}
Si noti che questo approccio può gestire solo comandi semplici senza reindirizzamenti. Non può gestire reindirizzamenti, pipeline, cicli for/while, istruzioni if, ecc.
Un altro caso d'uso comune è quando si esegue curl
con più campi di intestazione e payload. Puoi sempre definire argomenti come sotto e invocare curl
sul contenuto dell'array espanso
curlArgs=('-H' "keyheader: value" '-H' "2ndkeyheader: 2ndvalue")
curl "${curlArgs[@]}"
Un altro esempio,
payload='{}'
hostURL='http://google.com'
authToken='someToken'
authHeader='Authorization:Bearer "'"$authToken"'"'
ora che le variabili sono definite, usa un array per memorizzare il tuo comando args
curlCMD=(-X POST "$hostURL" --data "$payload" -H "Content-Type:application/json" -H "$authHeader")
e ora esegui una corretta espansione tra virgolette
curl "${curlCMD[@]}"
var=$(echo "asdf")
echo $var
# => asdf
Utilizzando questo metodo, il comando viene immediatamente valutato e il suo valore restituito viene memorizzato.
stored_date=$(date)
echo $stored_date
# => Thu Jan 15 10:57:16 EST 2015
# (wait a few seconds)
echo $stored_date
# => Thu Jan 15 10:57:16 EST 2015
Lo stesso con il backtick
stored_date=`date`
echo $stored_date
# => Thu Jan 15 11:02:19 EST 2015
# (wait a few seconds)
echo $stored_date
# => Thu Jan 15 11:02:19 EST 2015
Usando eval nel $(...)
non lo farà valutare in seguito
stored_date=$(eval "date")
echo $stored_date
# => Thu Jan 15 11:05:30 EST 2015
# (wait a few seconds)
echo $stored_date
# => Thu Jan 15 11:05:30 EST 2015
Utilizzando eval, viene valutato quando eval
viene utilizzato
stored_date="date" # < storing the command itself
echo $(eval "$stored_date")
# => Thu Jan 15 11:07:05 EST 2015
# (wait a few seconds)
echo $(eval "$stored_date")
# => Thu Jan 15 11:07:16 EST 2015
# ^^ Time changed
Nell'esempio precedente, se devi eseguire un comando con argomenti, inseriscili nella stringa che stai memorizzando
stored_date="date -u"
# ...
Per gli script bash questo è raramente rilevante, ma un'ultima nota. Fai attenzione con eval
. Valuta solo le stringhe che controlli, mai le stringhe provenienti da un utente non attendibile o create dall'input di un utente non attendibile.
- Grazie a @CharlesDuffy per avermi ricordato di citare il comando!