Con bash, configura le impostazioni glob in modo che le corrispondenze mancanti non generino un errore:
shopt -u failglob # avoid failure report (and discarding the whole line).
shopt -s nullglob # remove (erase) non-matching globs.
ls ?c c?
Il punto interrogativo è un carattere globale che rappresenta un singolo carattere. Dal momento che vuoi nomi di file a due caratteri, uno di questi deve essere un c , quindi è il primo carattere o l'ultimo carattere.
Con shopt -s dotglob questo farebbe emergere anche un file chiamato .c .
Se non ci sono file corrispondenti, l'impostazione di queste opzioni della shell provoca la rimozione di tutti gli argomenti, risultando in un semplice ls -- elenca qualsiasi cosa per impostazione predefinita.
Usa invece questo:
shopt -s nullglob ## drop any missing globs
set -- ?c c? ## populate the example@unixlinux.online array with (any) matches
if [ $# -gt 0 ] ## if there are some, list them
ls -d "example@unixlinux.online"
fi
Penso che il modo migliore sia usare find :
find . -type f -name '*c*' -name '??'
Questo cercherà in modo ricorsivo. Per elencare solo i file nella directory corrente:
find . ! -name . -prune -type f -name '*c*' -name '??'
Se i file esistono (e non hanno caratteri di escape come \c ), puoi utilizzare un glob:
echo ?c c?
che corrisponderà ai file che hanno un carattere (? ) seguito da un c o che hanno un c seguito da un carattere (? ).
Ma fallirà con i nomi di file che iniziano con un trattino come -n o -e o con caratteri backslash come \c o \n con echo sia come -e e -n sono speciali per (alcune shell) echo e \c o \n verrebbe interpretato come una sequenza di escape (\c termina l'output e \n stampa una nuova riga, non i caratteri letterali \n in alcune implementazioni shell di echo e con bash quando l'opzione shopt -s xpg_echo è impostato). Altre applicazioni o utilità (come ls ) avrà alcune altre opzioni e potrebbe non riuscire con molti altri caratteri avviati da trattino o interpretare altri caratteri di escape nei nomi di file.
Elencherà anche un file chiamato cc due volte.
-
Se un file può iniziare con un trattino (come -n), usa:
$ ls -d -- ?n -nO meglio:
$ ls -d ./?n ./-n
Avvertenze
-
Glob non corrisponde a nessun file.
-
Se i file non esistono, il glob non verrà espanso e verrà stampato nella sua forma originale.
$ echo ?m m? ?m m? -
Tranne in zsh.
$ zsh -c 'echo ?m m?' zsh:1: no matches found: ./m?La shell uscirà con un errore.
Questo comportamento è controllato danomatchdi Zsh opzione.$ zsh -c 'setopt +o nomatch; echo ?m m?' ?m m?Oppure:
$ zsh -c 'echo ?m(N) m?(N)' ?m m?Ma questo stamperà
mmdue volte. -
In bash potresti ottenere un risultato simile a zsh se l'opzione shell
failglobè impostato:$ bash -c 'shopt -s failglob; echo ?m m?' bash: no match: ?mMa lo script non si fermerà, la shell non uscirà. Bene, tecnicamente, la riga in cui viene utilizzato il glob non viene eseguita ulteriormente, ma l'esecuzione riprende dalla riga di script successiva.
-
In bash puoi impostare l'opzione
nullglobper rimuovere i glob che non corrispondono:$ bash -c 'shopt -s nullglob; echo ?m m? done' done
-
-
Usando ls (simile ad altri programmi)
-
Con i file corrispondenti non ci saranno problemi, ma corrisponderanno (ed elencheranno) anche le directory:
$ ls ?c c? bc cz sc ac: hjkMeglio usare
-dconls(le directory saranno incluse ma non espanse).$ ls -d ?c c? ac bc cz sc -
I glob non riescono a trovare una corrispondenza con un file (o una directory)
Poi
lsriporterà un errore$ ls ?m m? ls: cannot access '?m': No such file or directoryAltri programmi potrebbero (probabilmente) non fare controlli simili.
-
Usando
nullglobcon bash darà un elenco vuoto a ls, quindi elencherà i contenuti o il pwd come se sololsè stato eseguito:$ ls ?m m? ac a.out cz 3 b sc ab bcQuesto potrebbe essere evitato usando
./$ ls -d ./?m ./m? ls: cannot access './?m': No such file or directory ls: cannot access './m?': No such file or directory
-
Oppure puoi usare una regex find (ma attraverserà le sottodirectory con prune missing) (Notare che questo non ripeterà un file chiamato cc):
$ find . ! -name . -prune -regex '.*/\(.c\|c.\)'
./ac
./cc
./sc
./bc
./cz