La scelta è tua. Se non citate $@
nessuno dei suoi valori subite ulteriori espansioni e interpretazioni. Se lo citate, tutti gli argomenti passati vengono riprodotti alla lettera nella sua espansione. Non sarai mai in grado di gestire in modo affidabile token di sintassi della shell come &>|
ed ecc. In entrambi i modi senza analizzare gli argomenti tu stesso - e quindi ti rimangono le scelte più ragionevoli di consegnare la tua funzione in uno dei seguenti modi:
- Esattamente le parole usate nell'esecuzione di un singolo comando semplice con
"$@"
.
...o...
- Un'ulteriore versione ampliata e interpretata dei tuoi argomenti che solo successivamente vengono applicati insieme come un semplice comando
$@
.
In nessun caso è sbagliato se è intenzionale e se gli effetti di ciò che si sceglie sono ben compresi. Entrambe le vie presentano vantaggi l'una rispetto all'altra, sebbene raramente i vantaggi della seconda siano particolarmente utili. Ancora...
(run_this(){ $@; }; IFS=@ run_this 'ls@-dl@/tmp')
drwxrwxrwt 22 root root 660 Dec 28 19:58 /tmp
... non è inutile , solo raramente può essere di grande utilità . E in una bash
shell, perché bash
per impostazione predefinita non si attacca una definizione di variabile al suo ambiente anche quando detta definizione è anteposta alla riga di comando di un builtin speciale o a una funzione, il valore globale per$IFS
non è interessato e la sua dichiarazione è locale solo per la run_this()
chiamata.
Allo stesso modo:
(run_this(){ $@; }; set -f; run_this ls -l \*)
ls: cannot access *: No such file or directory
... il globbing è anche configurabile. Le citazioni servono a uno scopo - non sono per niente. Senza di essi l'espansione della shell subisce un'interpretazione extra - interpretazione configurabile . In passato, con alcune shell molto vecchie , $IFS
veniva applicato a livello globale a tutti gli input e non solo alle espansioni. In effetti, le shell si sono comportate in modo molto simile run_this()
a quello in cui hanno rotto tutte le parole di input sul valore di $IFS
. E quindi, se quello che stai cercando è quel comportamento shell molto vecchio, allora dovresti usare run_this()
.
Non lo sto cercando, e al momento sono abbastanza difficile da trovare un esempio utile. In genere preferisco che i comandi eseguiti dalla mia shell siano quelli che scrivo. E così, data la scelta, quasi sempre run_that()
. Salvo che...
(run_that(){ "$@"; }; IFS=l run_that 'ls' '-ld' '/tmp')
drwxrwxrwt 22 root root 660 Dec 28 19:58 /tmp
Quasi tutto può essere citato. I comandi verranno eseguiti tra virgolette. Funziona perché quando il comando viene effettivamente eseguito, tutte le parole di input sono già state sottoposte a rimozione delle virgolette, che è l'ultima fase del processo di interpretazione dell'input della shell. Quindi la differenza tra 'ls'
e ls
può importare solo mentre la shell sta interpretando - ed è per questo che la citazione ls
assicura che qualsiasi alias nominato ls
non sia sostituito dalla mia ls
parola di comando tra virgolette . A parte questo, le uniche cose che influenzano le citazioni sono la delimitazione delle parole (che è come e perché funziona la citazione di variabili / input-spazi bianchi) e l'interpretazione di metacaratteri e parole riservate.
Così:
'for' f in ...
do :
done
bash: for: command not found
bash: do: unexpected token 'do'
bash: do: unexpected token 'done'
Non sarai mai in grado di farlo con nessuno dei due run_this()
o run_that()
.
Ma i nomi delle funzioni, $PATH
i comandi o i builtin eseguiranno solo virgolette o non quotate, ed è esattamente come run_this()
e come run_that()
funziona in primo luogo. Non sarai in grado di fare nulla di utile con $<>|&(){}
nessuno di questi. A corto di eval
, è.
(run_that(){ "$@"; }; run_that eval printf '"%s\n"' '"$@"')
eval
printf
"%s\n"
"$@"
Ma senza di esso, sei vincolato ai limiti di un semplice comando in virtù delle virgolette che usi (anche quando non lo fai perché si $@
comporta come una citazione all'inizio del processo quando il comando viene analizzato per i metacaratteri) . Lo stesso vincolo vale per le assegnazioni e i reindirizzamenti della riga di comando, che sono limitati alla riga di comando della funzione. Ma questo non è un grosso problema:
(run_that(){ "$@";}; echo hey | run_that cat)
hey
Avrei potuto facilmente <
reindirizzare input o >
output lì come ho aperto la pipe.
Ad ogni modo, in modo circolare, non esiste un modo giusto o sbagliato qui - ogni modo ha i suoi usi. È solo che dovresti scriverlo come intendi usarlo e dovresti sapere cosa intendi fare. Citazioni omettendo possono avere uno scopo - altrimenti non ci sarebbe essere citazioni a tutti - ma se li si omette, per motivi che non interessano al vostro scopo, sei solo a scrivere codice cattivo. Fai quello che vuoi dire; Ci provo comunque.
run_that
Il comportamento è sicuramente quello che mi aspetterei (e se ci fosse uno spazio nel percorso del comando?). Se volessi l'altro comportamento, sicuramente lo annulleresti nel sito della chiamata dove sai quali sono i dati? Mi aspetto di chiamare questa funzione comerun_that ls -l
, che funziona allo stesso modo in entrambe le versioni. C'è un caso che ti ha fatto aspettare in modo diverso?