Concatenazione di stringhe di bash utilizzata per creare l'elenco di parametri


12

Dato questo pezzo di bash:

PARMS='-rvu'
PARMS+=" --delete --exclude='.git'"
echo $PARMS
rsync ${PARMS} . ${TARGET}

L'eco mostra la stringa PARMS come previsto, non viene visualizzato alcun errore, ma rsync agisce silenziosamente come se le opzioni aggiunte da + = non esistessero. Tuttavia, funziona come previsto:

PARMS='-rvu'
rsync ${PARMS} --delete --exclude='.git' . ${TARGET}

Immagino di aver rovinato qualcosa con le virgolette bash (ho sempre avuto problemi con quelli), ma non sono esattamente sicuro di cosa e perché le opzioni vengano ignorate anche se la stringa sembra essere stata costruita correttamente.


1
echo "$PARMS"e rsync "${PARMS}"...
Jasonwryan,

Questo funziona per me con la bashversione 4.2.25 senza alcuna modifica.
Anthon,

Risposte:


17

C'è una differenza tra:

PARMS+="... --exclude='.git'"

e

... --exclude='.git'

Nel primo, le virgolette singole sono all'interno delle virgolette stesse, quindi sono letteralmente presenti nel testo sostituito dato rsynccome argomenti. rsyncottiene un argomento il cui valore è --exclude='.git'. Nel secondo, le virgolette singole vengono interpretate dalla shell nel momento in cui sono scritte, perché non sono all'interno delle virgolette stesse e rsyncvengono visualizzate --exclude=.git.

In questo caso, non hai assolutamente bisogno delle virgolette singole: .gitè una parola shell perfettamente valida da sola, senza caratteri speciali, quindi puoi usarla letteralmente nel comando.

Meglio per questo tipo di cose, però, è un array :

PARMS=(-rvu)
PARMS+=(--delete --exclude='.git')
rsync "${PARMS[@]}"

Questo costruisce il tuo comando come parole separate, con qualunque citazione tu voglia interpretare nel momento in cui scrivi la riga dell'array. "${PARMS[@]}"si espande a ciascuna voce dell'array come argomento separato, anche se l'argomento stesso contiene caratteri o spazi speciali, quindi rsyncvede ciò che hai scritto nel modo in cui lo intendevi.


bashha eseguito la divisione delle parole dopo l' ${PARMS}espansione. Quindi la singola citazione è stata interpretata anche dalla shell.
cuonglm,

2
Provalo! L'ho fatto. Le virgolette rimangono e se ci sono spazi tra loro sono comunque punti di divisione.
Michael Homer,

@Gnouc: Dalla pagina man di bash: "Quote Rimozione: Dopo le precedenti espansioni, tutte le occorrenze non quotate dei personaggi \ , 'e "., Che non è stato determinato da una delle espansioni di cui sopra vengono rimossi" "above expansions" include Parameter Expansion che esegue l'espansione di ${PARMS}.
Camh,

Grazie. Quindi capisco che in quel caso omettere le virgolette singole all'interno di quelle doppie funzionerà, ma per completezza - e se avessi bisogno di citare alcuni caratteri speciali e non volessi usare il tuo ultimo approccio?
neuviemeporte,

Se i tuoi personaggi speciali non fanno parte di IFS(generalmente spazi bianchi), non è necessario citarli. Se lo sono, sei sfortunato a meno che tu non modifichi qualcosa insieme eval- questo è un po 'un malfunzionamento in generale e gli array sono il modo giusto per affrontarlo.
Michael Homer,

2

Oltre alla risposta di @Michael Homer , puoi usare la bash funzione eval :

PARMS='-rvu'
PARMS+=" --delete --exclude='.git'"
echo "$PARMS"
eval "rsync ${PARMS} . "'"${TARGET}"'

2
Puoi, ma non dovresti. Le matrici sono state aggiunte specificamente per evitare questo uso di eval.
Chepner,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.