2011-09-17 5 views
21

Genero una variabile bash contenente tutti i miei argomenti e quegli argomenti contengono spazi. Quando lancio un comando con questi argomenti - es. ls $ args - le virgolette non sono interpretate correttamente. Ecco un esempio: crea e cancella anche i file necessari.bash - variabile contenente più argomenti con le virgolette

#!/bin/bash 
f1="file n1" 
f2="file n2" 
# create files 
touch "$f1" "$f2" 
# concatenate arguments 
args="\"$f1\" \"$f2\"" 
# Print arguments, then launch 'ls' command 
echo "arguments :" $args 
ls $args 
# delete files 
rm "$f1" "$f2" 

Con questo, ho alcuni errori "No such file" per "archiviare, n1", "File e n2"

+0

http://stackoverflow.com/questions/2005192/how-to-execute-a-bash-command-stored-as-a-string-with -quotes-and-asterisk –

risposta

38

Si potrebbe considerare l'utilizzo di un array per il args, qualcosa del genere:

args=("$f1" "$f2") 
ls "${args[@]}" 

(Il problema che stai colpendo al momento è che una volta in la terpolazione è avvenuta non c'è differenza tra gli spazi intra- e tra i nomi dei file.)

+3

Funziona solo con shell come Bash che supportano gli array. 'eval' descritto di seguito funziona con tutte le shell Unix. –

+0

@ arran-cudbard-bell Beh, è ​​vero, ma la domanda menziona più volte 'bash', quindi questa soluzione sembra la migliore risposta. – monnef

+1

Non sono d'accordo, per me la sintassi è strana e opaca. –

2

Utilizzare set per impostare le variabili come parametri posizionali; quindi le virgolette verranno mantenute se ci si riferisce a esse tramite "$ @" o "$ 1", "$ 2", ecc. Assicurarsi di utilizzare le doppie virgolette tra i nomi delle variabili.

set -- "$f1" "$f2" 
touch "[email protected]" 
ls "[email protected]" 
rm "[email protected]" 
3

Questa è probabilmente la risposta peggiore, ma è possibile modificare IFS. Questo è il "separatore di campo interno" ed è uguale allo spazio + tab + newline di default.

#!/bin/sh 
IFS=, 
MAR="-n,my file" 
cat $MAR 

Lo script precedente verrà eseguito cat. Il primo argomento sarà -n (righe numerate) e il secondo argomento sarà my file.

26

Utilizzare eval per valutare prima eventuali espansioni e quotature e quindi eseguire la stringa risultante come se fosse stata digitata nella shell.

args="'$f1' '$f2'" 
eval ls $args 

eval sarà poi esegue ls 'file n1' 'file n2'

ha avuto un problema molto simile, cercando di passare gli argomenti a variabili provenienti /etc/default/-start_stop_daemon negli script di init.

+1

Downvoted perché 'eval' ha seri problemi di sicurezza - vedi http://stackoverflow.com/a/37573041/120818 per una spiegazione più dettagliata, ma in pratica (da http: //mywiki.wooledge.org/BashFAQ/048): "Fa sì che il codice venga analizzato due volte anziché una volta: ciò significa che, ad esempio, se il codice contiene riferimenti variabili, il parser della shell valuterà il contenuto di tale variabile. contiene un comando shell, la shell potrebbe eseguire quel comando, che tu lo volessi o meno. " – HerbCSO

+3

È come dire che non si dovrebbe mai usare goto in programmazione C perché alcuni sviluppatori li usano per trasformare il codice in un nido di topi. Ci sono molti casi in cui eval non introdurrà problemi di sicurezza, non vedo davvero che questa sia una critica valida. –

+2

Sono d'accordo con @ ArranCudbard-Bell. Stai già eseguendo codice potenzialmente arbitrario con gli argomenti variabili. L'uso di 'eval' non consente al codice di fare qualcosa di più di quanto non potrebbe già nelle circostanze. – siride

0

Ecco la mia ricetta per concatenare argomenti citati - utilizzati principalmente per mantenere leggibile lo script. Ma è anche comodo per commentare alcuni argomenti fuori facilmente:

PARAM1="a param with white spaces" 
PARAM2="some other funny param" 
PARAM3="third spaced param" 
#... 

PARAMS=$PARAM1 
PARAMS+='" "' 
PARAMS+=$PARAM2 
PARAMS+='" "' 
PARAMS+=$PARAM3 
#... 

eval command '"'$PARAMS'"'