2010-07-19 10 views
5

in SH:Non riesco a capire la sostituzione di comando in crostacei

~$ `echo ls` 
bin/ Desktop/ 

Ma nel pesce: (. Si noti che viene visualizzato il messaggio di errore di sopra della linea di comando)

fish: Illegal command name “(echo ls)” 
~% (echo ls) 

~% echo (echo ls) 
ls 
~% eval (echo ls) 
bin/ Desktop/ 

fish: Illegal command name “(echo ls)” 
exec (echo ls) 
    ^
~% exec (echo ls) 

Sembra che la sostituzione di comando funzioni solo come parametri di un comando, non come un comando stesso? Perché?

Bene, l'aiuto doc fa dire

Se un parametro contiene una serie di parentesi, il testo racchiuso tra parentesi sarà interpretato come un elenco di comandi.

Ma ancora, perché?

+0

Poiché il messaggio di errore sopra la linea di comando e sembra che lo hai poi modificato prima di inviarlo di nuovo, è confuso poiché nessuno dei comandi mostrati produce quell'errore. Forse dovresti inserire '(echo ls)' dopo il messaggio di errore per chiarezza. –

+0

Mi dispiace, mi manca il '()'. Modificato. – weakish

risposta

4

Come

Questo perché le sostituzioni comando appartengono a espansioni dei parametri e non sono ammessi come comandi.

Un esempio simile:

in SH:

tmpls=ls 
$tmpls 

Ma nel pesce:

% set cmd ls; $cmd 
fish: Variables may not be used as commands. 
... 

Perché

In breve, è un bene per verificabilità

Questo article spiega i dettagli:

Dal momento che è consentito l'uso di variabili come comandi di shell regolare, è impossibile controllare in modo affidabile la sintassi di uno script. Ad esempio, questo snippet di codice bash/zsh potrebbe essere o non essere legale, a seconda della tua fortuna. Ti senti fortunato?

if true; then if [ $RANDOM -lt 1024 ]; then END=fi; else END=true; fi; $END 

Sia bash e zsh cercare di determinare se il comando nel buffer corrente termina quando l'utente preme il tasto di ritorno, ma a causa di problemi come questo, saranno talvolta sicuro. Ancora peggio, questo pezzo di codice perfettamente legale è respinta da bash:

FI=fi; foo() { if true; then true; $FI; } 

Pesce evita questo tipo di problema, dal momento che le variabili non sono ammessi come comandi. Tutto ciò che puoi fare con le variabili come comandi può essere fatto in un modo molto più pulito usando il comando eval o usando le funzioni.

Per lo stesso motivo, le sostituzioni di comando non sono consentite come comandi.

(Nota:. L'esempio citato non è giusto, dal momento che 'se' e 'fi' non sono semplici comandi, ma le parole riservate Vedere i commenti qui sotto.)

+0

Per una discussione su questo problema riguardante Bash, vedere [BashFAQ/050] (http://mywiki.wooledge.org/BashFAQ/050). –

+1

l'articolo che citi nella sezione "perché" è errato (almeno per quanto riguarda questa sezione). Un comando come 'FI = fi; foo() {se è vero; allora vero; $ FI; } 'is * not * sintassi della shell valida, quindi è correttamente contrassegnata come errore di sintassi da tutte le shell POSIX. Parole come 'fi' sono parole riservate, e sono riconosciute prima dell'espansione delle parole che espande' $ FI' in 'fi'. – Gilles

+0

@Gilles Grazie. Ho modificato la mia risposta. – weakish

0

Ha a che fare con l'ordine delle espansioni.

Da help expand-command-substitution in fish:

Quando combinando più espansioni di parametri, espansioni vengono eseguite nel seguente ordine:

* Command substitutions 
* Variable expansions 
* Bracket expansion 
* Pid expansion 
* Wildcard expansion 

Espansioni vengono eseguite da destra verso sinistra, annidati le espansioni della staffa vengono eseguite dall'interno e dall'esterno.

Da man bash:

L'ordine di espansione è: espansione delle parentesi graffe, espansione della tilde, un parametro variabile e sostituzione di espansione e comando aritmetica (fatto in sinistra a destra moda), parola splitting e espansione del pathname.

+0

Sono ancora confuso. Sembra che il pesce non tenti di espandere la sostituzione del comando e prende (echo ls) letteralmente come comando. – weakish

Problemi correlati