Interrompere l'espansione dei caratteri jolly della shell?


91

C'è un modo per un programma da riga di comando compilato per dire a bash o csh che non vuole che i caratteri jolly nei suoi parametri siano espansi?

Ad esempio, si potrebbe desiderare un comando di shell come:

foo *

per restituire semplicemente il valore ASCII numerico di quel carattere.

Risposte:


122

No. L'espansione avviene prima che il comando venga effettivamente eseguito.
Puoi disabilitare il glob solo prima di eseguire il comando o citando la stella.

$ # quote it
$ foo '*'

$ # or escape it
$ foo \*

$ # or disable the glob (noglob)
$ set -f
$ foo *

$ # alternative to set -f
$ set -o noglob
$ # undo it by 
$ set +o noglob

3
inoltre, se non c'è niente da espandere, non c'è espansione. cioè con un vuoto pwd, echo *è solo*
sam boosalis

7
@sam In realtà dipende da come sono impostate le opzioni. Da tldp: "Se non vengono trovati nomi di file corrispondenti e l'opzione della shell nullglobè disabilitata, la parola rimane invariata. Se l' nullglobopzione è impostata e non viene trovata alcuna corrispondenza, la parola viene rimossa."
Chris Middleton

grazie, avrei dovuto precisare che era solo un'osservazione, non una comprensione.
sam boosalis

@ c00kiemon5ter Come annullare il set -f? È vero unset -f?
Nam G VU

1
@NamGVUset +f
Yngvar Kristiansen,

63

Sebbene sia vero che un comando stesso non può disattivare il globbing, è possibile che un utente dica a una shell Unix di non glob un comando particolare. Questo di solito si ottiene modificando i file di configurazione di una shell. Supponendo che il comando foopossa essere trovato lungo il percorso del comando, è necessario aggiungere quanto segue al file di configurazione appropriato:

Per le shell sh, bash e ksh:

alias foo='set -f;foo';foo(){ command foo "$@";set +f;}

Per le shell csh e tcsh:

alias foo 'set noglob;\foo \!*;unset noglob'

Per la shell zsh:

alias foo='noglob foo'

Non è necessario utilizzare il percorso del comando. Supponiamo che il comando foo sia memorizzato nella directory ~ / bin, quindi il precedente diventerebbe:

Per le shell sh, bash e ksh:

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

Per le shell csh e tcsh:

alias foo 'set noglob;$home/bin/foo \!*;unset noglob'

Per la shell zsh:

alias foo='noglob ~/bin/foo'

Tutto quanto sopra è stato testato utilizzando OSX 10.9.2 di Apple. Nota: quando si copia il codice precedente, fare attenzione a eliminare eventuali spazi. Possono essere significativi.

Aggiornare:

L'utente geira ha sottolineato che nel caso di una shell bash

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

potrebbe essere sostituito con

reset_expansion(){ CMD="$1";shift;$CMD "$@";set +f;}
alias foo='set -f;reset_expansion ~/bin/foo'

che elimina la necessità della funzione foo.

Alcuni siti web utilizzati per creare questo documento:


3
Questa avrebbe dovuto essere la risposta accettata in quanto dimostra che è effettivamente possibile fare ciò che vuole il PO. Per alcuni metodi ancora migliori in bash, questo collegamento documenta le varie opzioni: blog.edwards-research.com/2011/05/preventing-globbing
geira

@geira: a volte viene accettata una risposta prima che venga pubblicata una risposta migliore. Credo che questo possa essere uno di quei casi. Credo anche che la risposta segna come più utile dagli utenti finisca per prima. Nota: ho aggiunto il tuo contributo alla mia risposta.
David Anderson,

@geira, l'OP vuole che il programma compilato comunichi con la shell; rispondere che è possibile configurare la shell in modo che si comporti come desiderato su una base comando per comando è una risposta utile, e io stesso accetterei questa, ma vedo spazio per non essere d'accordo sul fatto che sia interamente puntuale.
Charles Duffy

Il fatto che possa essere fatto non significa che debba essere fatto. Il fatto che il comportamento della shell cambi rispetto alle ragionevoli aspettative dell'utente per i comandi di selezione sembra sorprendente e in definitiva indesiderabile.
tripleee

@ tripleee: C'è stato un tempo in cui le persone si aspettavano relè e valvole a vuoto. Sono attesi buchi nelle carte di cartone e nel nastro di carta. Le persone possedevano regole a scorrimento invece di calcolatrici e telefoni. Suppongo che per te questo sarebbe desiderabile. Non mi importava molto di quei tempi. Mi piace vedere cosa c'è dopo.
David Anderson,

8

L'espansione viene eseguita dalla shell prima che il programma venga eseguito. Il tuo programma non ha la più pallida idea se l'espansione sia avvenuta o meno.

   set -o noglob

disattiverà l'espansione nella shell di invocazione, ma dovresti farlo prima di invocare il tuo programma.

L'alternativa è citare i tuoi argomenti, ad es

foo "*"

4
setopt sembra essere un comando specifico per zsh. Come ha detto un altro poster, per bash si utilizza set -o noglobper disabilitare l'espansione dei caratteri jolly.
Wirawan Purwanto

Ora modificato. Grazie
Brian Agnew

1

Attenzione: se non ci sono nomi che corrispondono alla maschera, bash passa l'argomento così com'è, senza espansione!

Prova (pa.py è uno script molto semplice, che stampa solo i suoi argomenti):

 $ ls
f1.cc  f2.cc  pa.py
 $ ./pa.py *.cc
['./pa.py', 'f1.cc', 'f2.cc']
 $ ./pa.py *.cpp
['./pa.py', '*.cpp']

3
Non sempre. set -o nullgloboppure shopt -s failglob, e questo comportamento cambierà (in due modi molto diversi).
Charles Duffy
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.