2015-07-14 17 views
7

Ho appreso che le espansioni dei nomi dei file vengono eseguite prima dell'esecuzione dei comandi quando si eseguono i comandi in Bash. Ma quando si cerca i comandi indicati di seguito (con l'opzione -x):Espansione del nome file negli argomenti "a = b" -like dei comandi incorporati di Bash

touch foo=3 # Create a file with name "foo=3" 
+ touch foo=3 
declare foo=? 
+ declare 'foo=?' 
alias foo=* 
+ alias 'foo=*' 

non ottengo quello che mi aspettavo, perché foo =? e foo = * non sono espanse al nome del file "foo = 3":

declare -p | grep 'foo=' # => foo='?' 
alias | grep 'foo='   # => alias foo='*' 

Ma se corro un built-in come cd o una funzione che accetta un incarico come parametro scritta da me, come mi viene show_rhs() { echo "${1%=*}='${1#*=}'"; } cosa mi aspetto (foo =? and foo = * sono espansi).

cd foo=?   # => foo=3: Not a directory 
show_rhs() foo=* # => foo='3' 

L'unica differenza che posso vedere qui è dichiarano e alias sono built-in E accettare un incarico come parametro. Sembra che venga aggiunta una coppia di citazioni per racchiudere il compito prima delle espansioni dei nomi dei file in base all'output dell'opzione -x.

Ma se l'espansione del nome file viene eseguita prima dell'esecuzione del comando indipendentemente da quale sia il comando, l'argomento passato in declare e alias deve essere foo = 3 anziché foo =? e foo = * a causa della presenza del file "foo = 3".

Quindi Bash fa qualcosa di speciale (magari citando i caratteri jolly?) Su argomenti "a = b", a seconda dei comandi prima delle espansioni dei nomi dei file?

(Il mio ambiente: CentOS 5.8 a 64 bit, GNU Bash 3.2.25)

+0

Alias ​​e variabili vivono in diversi spazi dei nomi. Puoi assolutamente avere un alias e una variabile con lo stesso nome.Una variabile creata con un compito semplice e una creata con 'declare' sono la stessa cosa anche se così' foo = 3; declare foo =? 'ti lascia con una variabile' pippo' con il valore '?'. Sei sicuro di ottenere gli errori che rivendichi per queste ultime due righe? Perché non vedo come sia possibile. Nessuno di questi contesti valuterà le variabili (e il secondo non è nemmeno una linea di shell valida e dovrebbe darti un errore su un token imprevisto). –

+0

Ci scusiamo per la confusione. Non volevo dire se fosse possibile creare una variabile e un alias con lo stesso nome. Intendo entrambi foo =? and foo = * dovrebbe essere espanso a foo = 3 a causa della presenza del file "foo = 3" prima di essere passato in quei comandi, quindi sia la variabile che l'alias dovrebbero avere un valore di "3" piuttosto che l'originale jolly. Il codice di dichiarazione e alias sono solo esempi. – ebk

+0

Ah, ok. Ho quasi commentato un file 'foo = 3' ma ho pensato che fosse improbabile (e non l'hai menzionato nel post). Ma sì, penso che la tua ipotesi sia corretta. Il fatto che quei built-in accettino assegnazioni direttamente significa che il normale comportamento di espansione glob non si verifica lì. (Non succede nemmeno per 'foo =?') Probabilmente c'è qualcosa nelle specifiche POSIX su questo. Posso provare a guardare dopo. –

risposta

2

Bash analizza alcuni dei suoi comandi incorporati in un modo che non è strettamente conforme Posix, e anche non molto ben documentato.

In particolare, argomenti assegnazione di comandi che accettano tali argomenti (alias, declare, export, local, readonly e typeset) non sono soggette a Espansione di percorso né la suddivisione in parole. (Questo è fatto internamente sopprimendo le espansioni, non citando i metacaratteri, anche se non è facile vedere come dettaglio attuazione potrebbe diventare visibile.)

Ciò avviene anche se bash viene avviato in modalità Posix o come sh.

Si noti che la soppressione dell'espansione del percorso si applica solo agli argomenti che assomigliano ai compiti. Estendendo l'esempio dalla domanda:

touch foo=3 # Create a file with name "foo=3" 
+ touch foo=3 
declare foo=? 
+ declare 'foo=?' 

bar="foo=?" # Put the declare argument in a variable 
+ bar='foo=?' 
declare $bar 
+ declare foo=3 

Come previsto, dash percorso espande e word-divide argomenti per alias e export, in linea con le specifiche Posix. Quindi, a quanto pare, fa zsh.

Tranne che nella modalità Posix, bash anche tilde-espande il lato destro degli argomenti che assomigliano a compiti. In modalità Posix, limita questo agli argomenti di assegnazione dei builtin elencati sopra, sebbene Posix specifichi l'espansione tilde dopo = solo nelle assegnazioni di variabili prima della parola di comando. Questo è ciò che fa dash, ma zsh estende questo a "comandi della famiglia dei tipi" (documentato nello zsh manual).

+0

@ebk: la pagina che citi dice chiaramente che le assegnazioni di variabili "vengono prima del nome del comando", che è anche ciò di cui stavo parlando. (Questo include i compiti in cui non vi è alcuna parola di comando.) – rici

+0

Spiacente, ho accidentalmente cancellato il mio commento precedente poiché non mi sono ancora abituato allo stackoverflow. Pubblica semplicemente [il link alla pagina] (http://www.gnu.org/software/bash/manual/html_node/Simple-Command-Expansion.html) di nuovo come riferimento per gli altri. Non riesco a immaginare come mettere un'assegnazione di variabile prima di un nome di comando in un comando semplice, eccetto incarichi senza una parola di comando. Puoi farmi un esempio? – ebk

+2

@ebk: se si inserisce un compito prima della parola di comando, l'assegnazione si applica solo all'ambiente passato al comando. L'esempio più comune è probabilmente 'IFS =, read -r a b c', in cui l'assegnazione a' IFS' non è visibile nello script, ma fa parte dell'ambiente usato dal comando 'read'. C'è una spiegazione più lunga con esempi nel primer di scripting della shell Apple, https://developer.apple.com/library/mac/documentation/OpenSource/Conceptual/ShellScripting/shell_scripts/shell_scripts.html#//apple_ref/doc/uid/TP40004268 -CH237-SW12 – rici