Shell Script: creazione di una variabile con opzioni all'interno


11

Ho un comando rsync con i seguenti parametri:

rsync -avz --{partial,stats,delete,exclude=".*"}

Voglio mettere quei parametri all'interno di una variabile per riutilizzarla dopo nello script. Qualcosa come questo:

#!/bin/bash
VAR=rsync -avz --{partial,stats,delete,exclude=".*"}
$VAR /dir1 /dir2

Ho provato con virgolette, virgolette singole, parentesi, senza alcun successo.



Avendo già seguito questa strada: assicurati che la stringa di comando risultante finale non contenga stringhe vuote. In tal caso, rsync può usarli come parametri e poiché sono invisibili, è piuttosto difficile eseguire il debug. Avevo un primo parametro vuoto e rsync lo interpretava come includendo la directory corrente nelle fonti delle cose da copiare.
Joe

Risposte:


12

Inserire un comando complesso in una variabile non è mai un approccio raccomandato. Vedi BashFAQ / 050 - Sto cercando di inserire un comando in una variabile, ma i casi complessi falliscono sempre!

Il tuo requisito diventa davvero semplice, se decidi di utilizzare una funzione anziché una variabile e passare argomenti ad essa.

Qualcosa di simile a

rsync_custom() {
    [ "$#" -eq 0 ] && { printf 'no arguments supplied' >&2; exit 1 ; }
    rsync -avz --{partial,stats,delete,exclude=".*"} "$@"
}

e ora passa gli argomenti richiesti come

rsync_custom /dir1 /dir2

La definizione della funzione è abbastanza semplice in un certo senso, per prima cosa controlliamo il conteggio degli argomenti di input usando la variabile $#che non dovrebbe essere zero. Viene visualizzato un messaggio di errore che dice che non vengono forniti argomenti. Se sono presenti argomenti validi, "$@"rappresenta gli argomenti effettivi forniti alla funzione.

Se questa è una funzione che useresti abbastanza frequentemente, ad esempio anche negli script / riga di comando, aggiungila .bashrc, .bash_profilead esempio , ai file di avvio della shell .

O come notato, potrebbe essere utile espandere l'espansione del controvento per separare gli argomenti per una migliore leggibilità

rsync_custom() {
    [ "$#" -eq 0 ] && { printf 'no arguments supplied' >&2; exit 1 ; }
    rsync -avz --partial --stats --delete --exclude=".*" "$@"
}

5
VAR=rsync -avz --{partial,stats,delete,exclude=".*"}

Questo tenta di eseguire il comando -avzcon argomenti --partial, --statsecc. E con VARimpostato su rsyncnell'ambiente.

VAR='rsync -avz --{partial,stats,delete,exclude=".*"}'

Il modulo tra virgolette non funziona perché le parentesi graffe non vengono espanse tra virgolette e non all'interno di assegnazioni, né vengono espanse dopo l'espansione di una variabile.

Se è necessario archiviare gli argomenti della riga di comando in una variabile, utilizzare un array:

args=(rsync -avz --{partial,stats,delete,exclude=".*"})

Ora "${args[@]}"si espanderà a rsync, -avz, --partial, ecc come parole distinte.

Le matrici consentono inoltre di aggiungere opzioni all'elenco, se necessario, in modo condizionale, in modo da poter ad esempio:

args=(this that)
if something ; then
    args+=(another_arg)
fi
"$cmd" "${args[@]}"

1

Puoi almeno salvare parzialmente le opzioni in una variabile:

opts=$(echo --{ignore-case,word-regexp,count,exclude='"sys*.*"'})

Il test è importante perché il mascheramento può essere difficile:

echo $opts
--ignore-case --word-regexp --count --exclude="sys*"

grep $opts bytes *.log 

Dato che ci sono più alternative, come usare la cronologia, usare un alias, usare una funzione, non c'è un caso d'uso ovvio a cui possa pensare. Raramente esiste una complessa opzione di condivisione tra diversi programmi, quindi per una soluzione ad hoc per la shell interattiva, l'aliasing sembra un modo migliore:

alias cgrep='grep --ignore-case --word-regexp --count --exclude="sys*"'
cgrep bytes *.log

Il tuo campione

VAR=rsync -avz --{partial,stats,delete,exclude=".*"}

non può funzionare, perché l'assegnazione è terminata al primo spazio vuoto. Devi mascherare gli spazi vuoti:

VAR='rsync -avz --{partial,stats,delete,exclude=".*"}'

una cosa piuttosto pericolosa per i test, con quell'opzione --delete, non è vero? Poiché le opzioni possono contenere di nuovo "," e virgolette singole, il mascheramento può diventare difficile molto presto. Vorrei fare un pseudonimo o fare affidamento sulla storia.

Un alias può essere archiviato nel file ~ / .bashrc per un uso continuo su più sessioni. Le funzioni possono essere memorizzate anche nel bashrc, ma sono necessarie solo se si desidera gestire i parametri, passati nella funzione per essere valutati al loro interno.

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.