Evitare errori dovuti ad asterisco non espanso


16

In bash utilizzo spesso for-loop come il seguente

for file in *.type; do 
  sommecommand "$file"; 
done;

per eseguire un'operazione per tutti i file corrispondenti *.type. Se non viene trovato alcun file con questa desinenza nelle directory di lavoro, l'asterisco non viene espanso e di solito ricevo un messaggio di errore che dice che un comando non ha trovato il file. Posso immediatamente pensare a diversi modi per evitare questo errore. Ma l'aggiunta di un condizionale non sembra essere molto elegante. C'è un modo breve e pulito per raggiungere questo obiettivo?

Risposte:


20

Sì, esegui il comando seguente:

shopt -s nullglob

annullerà la corrispondenza e non verrà attivato alcun errore.

  • se si desidera questo comportamento per impostazione predefinita, aggiungere il comando nel proprio ~/.bashrc
  • se si desidera rilevare un glob nullo nella shell POSIX, provare

    for i in *.txt; do
      [ "$i" = '*.txt' ] && [ ! -e '*.txt' ] && continue
    done

Vedi http://mywiki.wooledge.org/NullGlob


1
Si noti che in realtà è possibile avere un file chiamato *.txt. Vale la pena verificare se il file esiste.
Chris Down,

post modificato di conseguenza.
Gilles Quenot,

@ChrisDown Nota che lo stesso commento della tua risposta si applica qui (con conseguenze potenzialmente più gravi a causa del breakinvece di continue).
Stéphane Chazelas,

6

In bash puoi usare shopt -s nullglobper espandere in un array vuoto se non ci sono corrispondenze.

Nelle shell POSIX senza nullglob, puoi evitare questo problema controllando che il nome del file passato esista effettivamente avendo [ -e "$file" ] || [ -L "$file" ] || continuecome prima parte del tuo forciclo.


1
Si noti che non sarebbe strettamente equivalente poiché [ -erestituirebbe false per file inaccessibili o file che sono collegamenti simbolici a file inaccessibili o inesistenti.
Stéphane Chazelas,

@StephaneChazelas, fai riconoscere i punti sui symlink. Ma cosa hai in mente con "file inaccessibili"? Anche se io chmod 0 the_file, [ -e the_file ]valuto ancora vero, quindi deve essere qualcos'altro.
dubiousjim,

1
modifica inviata per gestire collegamenti simbolici non funzionanti. spero che vada bene.
dubiousjim,

2
@dubiousjim, mkdir -p x/{a,b} && chmod 444 x && echo x/* && [ -e x/a ]. x / a è inaccessibile ma poiché x è leggibile x / * si espande.
Stéphane Chazelas,

@StephaneChazelas, fantastico, grazie per avermi spiegato.
dubiousjim,

4

La solita tecnica per le shell che non hanno nullglobun'opzione è

set -- [*].type *.type
case $1$2 in
  '[*].type*.type') shift 2;;
  *) shift
esac
for file do
  cmd  -- "$file"
done

Il extra [*].typeè quello di coprire il caso in cui c'è un file chiamato *.typenella directory corrente.

Ora, se vuoi includere file dot, questo diventa più complicato .

Credo che questa tecnica sia stata coniata da Laura Fairhead su Usenet alcuni anni fa.


0

find . -name '*.type' -maxdepth 0 -exec somecommand "{}" ";"

Ciò rimuove del tutto il forloop e il gorgoglio della shell dall'equazione. findeseguirà il -execcomando una volta per corrispondenza e, se non ci sono corrispondenze, non verrà mai eseguito. Gli -maxdepth 0istruttori scoprono di non ricorrere nelle sottodirectory dell'argomento path chiamato ( ., in questo caso).

Il rovescio della medaglia è che coinvolge un'altra applicazione, sebbene sia presente praticamente su tutti i sistemi Linux là fuori (e probabilmente anche la maggior parte degli Unix).

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.