Risposte:
ls
elenca i file e il contenuto delle directory in cui viene passato come argomento e, se non viene fornito alcun argomento, elenca la directory corrente. Può anche essere passato una serie di opzioni che influenzano il suo comportamento (vedi man ls
per i dettagli).
Se ls
viene passato un argomento chiamato *
, cercherà un file o una directory chiamata *
nella directory corrente e lo elencherà come qualsiasi altro. ls
non tratta il *
personaggio in nessun altro modo rispetto a qualsiasi altro.
Tuttavia, se si ls *
tratta di una riga di comando della shell , la shell la espanderà in *
base alle regole di globbing della shell corrispondente (denominate anche Generazione nome file o Espansione nome file ).
Mentre conchiglie diverse supportano diversi operatori di globbing, la maggior parte di loro concorda su quella più semplice *
. *
come modello significa un numero qualsiasi di caratteri, così *
come glob
si espanderà all'elenco dei file nelle directory correnti che corrispondono a quel modello. C'è un'eccezione, tuttavia, che un carattere punto ( .
) in un nome di file deve essere abbinato in modo esplicito, quindi in *
realtà si espande all'elenco di file e directory che non iniziano con .
(in ordine lessicografico).
Per esempio, se la directory corrente contiene i file chiamati .
, ..
, .foo
, -l
e foo bar
, *
sarà ampliato dalla shell per due argomenti da passare a ls
: -l
e foo bar
, quindi sarà come se si fosse digitato:
ls -l "foo bar"
o
'ls' "-l" foo\ bar
Quali sono tre modi per eseguire esattamente lo stesso comando. In tutti e 3 i casi, al ls
comando (che probabilmente verrà eseguito da /bin/ls
una ricerca di directory menzionate in $PATH
) verranno passati questi 3 argomenti: "ls", "-l" e "foo bar".
Per inciso, in questo caso, ls
tratterà il primo (strettamente parlando secondo ) come un'opzione.
Ora, come ho detto, conchiglie diverse hanno operatori di globbing diversi. Qualche decennio fa, è stato zsh
introdotto l' **/
operatore¹, che significa abbinare qualsiasi livello di sottodirectory, abbreviazione di (*/)#
e ***/
che è lo stesso tranne che segue i collegamenti simbolici mentre si discendono le directory.
Qualche anno fa (luglio 2003 ksh93o+
), ksh93
decise di copiare quel comportamento, ma decise di renderlo facoltativo e coprì solo il **
caso (non ***
). Inoltre, anche se **
da solo non era speciale in zsh
(significava lo stesso che *
in altre shell tradizionali poiché **
significa qualsiasi numero di caratteri seguito da qualsiasi numero di caratteri), in ksh93, **
significava lo stesso di **/*
(quindi qualsiasi file o directory sotto quello corrente (esclusi i file nascosti).
bash
copiato ksh93
pochi anni dopo (febbraio 2009, bash 4.0), con la stessa sintassi, ma una differenza sfortunato: bash **
era come zsh
's ***
, che è vero stava seguendo i link simbolici quando recursing in sotto-directory che non è generalmente quello che vuoi fare e può avere effetti collaterali cattivi. Fu parzialmente risolto in bash-4.3 in quanto seguivano ancora i collegamenti simbolici, ma la ricorsione si fermò lì. È stato completamente risolto in 5.0.
yash
aggiunto **
nella versione 2.0 nel 2008, abilitato con l' extended-glob
opzione. La sua implementazione è più vicina a zsh
quella che **
da sola non è speciale. Nella versione 2.15 (2009), ha aggiunto ***
come in zsh
e due delle sue estensioni: .**
e .***
per includere directory nascoste durante la ricorrenza (in zsh
, il D
qualificatore glob (come in **/*(D)
) prenderà in considerazione file e directory nascosti, ma se si desidera solo attraversare nascosto dir ma non espandere i file nascosti, è necessario ((*|.*)/)#*
o **/[^.]*(D)
).
Anche la conchiglia di pesce supporta **
. Come la versione precedente di bash
, segue i collegamenti simbolici quando si discende dall'albero delle directory. In quella shell, tuttavia, **/*
non è lo stesso di **
. **
è più un'estensione *
che può comprendere diverse directory. In fish
, **/*.c
corrisponderà a/b/c.c
ma non a.c
, mentre a**.c
corrisponderà a.c
ed ab/c/d.c
e zsh
' **/.*
ad esempio deve essere scritto .* **/.*
. Lì, ***
è inteso come **
seguito da *
così lo stesso di **
.
tcsh
ha anche aggiunto globstar
un'opzione in V6.17.01 (maggio 2010) e supporta sia **
e ***
à la zsh
.
Quindi, in tcsh
, bash
e ksh93
, (quando l'opzione corrispondente è attivata ( globstar
)) o fish
, **
espande tutti i file e le directory sotto quello attuale, e ***
è la stessa **
per fish
, un collegamento simbolico attraversamento **
per tcsh
con globstar
, e lo stesso come *
in bash
e ksh93
(anche se è non è impossibile che anche le versioni future di quelle shell attraversino collegamenti simbolici).
Sopra, avrai notato la necessità di assicurarti che nessuna delle espansioni sia interpretata come un'opzione. Per quello, faresti:
ls -- *
O:
ls ./*
Ci sono alcuni comandi (non importa ls
) in cui il secondo è preferibile poiché anche con --
alcuni nomi di file possono essere trattati in modo speciale. E 'il caso della -
maggior parte dei programmi di utilità di testo, cd
e pushd
e nomi di file che contengono il =
carattere per awk
per esempio. La preparazione ./
a tutti gli argomenti rimuove il loro significato speciale (almeno per i casi sopra menzionati).
Va anche notato che la maggior parte delle shell ha una serie di opzioni che influenzano il comportamento globbing (come se i file dot sono ignorati o meno, l'ordine di ordinamento, cosa fare se non c'è corrispondenza ...), vedere anche il $FIGNORE
parametro inksh
Inoltre, in tutti i serbatoi ma csh
, tcsh
, fish
e zsh
, se il modello globbing non corrisponde a qualsiasi file, il modello è passato come parametro non espansa che provoca confusione ed eventualmente insetti. Ad esempio, se non ci sono file non nascosti nella directory corrente
ls *
In realtà chiamerà ls
con i due argomenti ls
e *
. E dato che non esiste alcun file, quindi nessuno dei *
due ha chiamato , vedrai un messaggio di errore da ls (non la shell) come:, ls: cannot access *: No such file or directory
che è stato conosciuto per far pensare alle persone che in ls
realtà stava espandendo i globs.
Il problema è ancora peggiore in casi come:
rm -- *.[ab]
Se non c'è *.a
né *.b
file nella directory corrente, allora si potrebbe finire per l'eliminazione di un file chiamato *.[ab]
per errore ( csh
, tcsh
, e zsh
potrebbe segnalare un fiammifero di errore e non lo chiamerei rm
(e fish
non supporta il [...]
jolly)).
Se vuoi passare un letterale *
a ls
, devi citare quel *
personaggio in qualche modo come in ls \*
o ls '*'
o ls "*"
. Nelle shell tipo POSIX, il globbing può essere disabilitato del tutto usando set -o noglob
o set -f
(quest'ultimo non funziona zsh
se non in sh
/ ksh
emulazione).
¹ Sebbene (*/)#
sia sempre stato supportato, è stato prima a corto di mano come ..../
in zsh-2.0 (e potenzialmente prima), poi ****/
in 2.1 prima di ottenere la sua forma definitiva **/
in 2.2 (inizio 1992)
find -name *
. Soprattutto con schemi più complessi, se esiste esattamente una corrispondenza nella directory corrente, le persone spesso non si renderanno conto di non passare l'asterisco find
.
*.[ab]
proverebbe a cancellare tutto finendo con .[ab]
. [
non è speciale nei pesci.
Il comando ls
predefinito è ls .
: Elenca tutte le voci nella directory corrente .
Il comando ls *
significa "esegui ls sull'espansione del *
modello di shell"
Il *
modello viene elaborato dalla shell e si espande a tutte le voci nella directory corrente, ad eccezione di quelle che iniziano con a .
. Passerà a un livello profondo.
L'interpretazione dei *
modelli doppi o tripli dipende dall'effettiva shell utilizzata.
*
è un carattere jolly che corrisponde a 0 o più caratteri. Alcune conchiglie moderne ricorrono in sottodirectory per vedere il **
modello.
*
fare aggiungere qualcosa, vedere l'altra risposta che spiega il globstar. Dovrebbe anche essere chiaro che ls non ha nulla a che fare con gli asterischi, non ha mai superato nessuno di questi asterischi. Corri echo ls *
per vedere cosa verrebbe eseguito quando scrivi ls *
.
Puoi demistificare l'intero processo digitando echo
anziché ls
prima, per vedere a cosa si espande il comando:
$ echo *
Applications Downloads Documents tmp.html
Quindi, in questo caso, si ls *
espande als Applications Downloads Documents tmp.html
$ echo **
Applications Downloads Documents tmp.html
$ echo ***
Applications Downloads Documents tmp.html
Quindi nessun cambiamento. Questo presuppone che tu stia usando bash
come shell - la maggior parte delle persone lo sono e diverse shell hanno comportamenti diversi. Se stai usando ash
o csh
o ksh
o zsh
, potresti aspettarti che le cose funzionino diversamente. Questo è il punto di avere conchiglie diverse.
Quindi proviamo qualcosa di diverso (ancora con bash
) in modo da farci un'idea dell'operatore globbing ( *
) che può fare per noi. Ad esempio, possiamo filtrare per parte del nome:
$ echo D*
Downloads Documents
È interessante notare che una barra finale è implicitamente una parte di qualsiasi nome di directory. Quindi */
produrrà solo le directory (e collegamenti simbolici alle directory):
$ echo */
Applications/ Downloads/ Documents/
E possiamo fare un po 'di filtraggio a più livelli mettendo le barre nel mezzo:
$ echo D*/*/
Documents/Work/ /Documents/unfinished/
Poiché la Downloads
directory non contiene alcuna sottodirectory, non finisce nell'output. Questo è molto utile solo per esaminare i file desiderati. Uso sempre comandi come questo:
$ ls -l /home/*/public_html/wp-config.php
Questo elenca, se ce ne sono, tutti i wp-config.php
file esistenti al livello base della public_html
directory di qualsiasi utente . O forse per essere più completo:
$ find /home/*/public_html/ -name wp-config.php
Questo troverà tutti i wp-config.php
file nelle directory di qualsiasi utente public_html
o in qualsiasi delle loro sottodirectory, ma funzionerà in modo più efficiente rispetto al semplice find /home/ -name wp-config.php
fatto che non esaminerà altro che le public_html
directory per ciascuno degli utenti.
bash
come shell" ← e che la globstar non sia abilitata. shopt -s globstar
e riprovare ...
set -x
che inizierà a stampare il comando "effettivo" eseguito ogni volta (spegnere con set +x
).
In alcune shell, incluso bash 4.x con l' globstar
opzione abilitata, **
eseguirà un glob ricorsivo, decrescente le directory corrispondenti. Asterischi aggiuntivi non modificano ulteriormente questa operazione.
ksh93
e zsh
, bash
attraversa i collegamenti simbolici nella ricorsione che è generalmente indesiderata.
Se vuoi "immergerti in profondità", usa l'opzione ls -R (ricorsiva) o usa trova, in questo modo:
find . -ls
"find" scenderà in fondo alla struttura ad albero delle directory (così come 'ls -R') e ha molte altre opzioni, come elencare directory (-type d), solo file (-type f) o mostrare file che hanno altri caratteristiche (nessun utente in / etc / passwd, permessi specifici e molto altro). "find" è anche un po 'più sicuro negli script (a causa di incoerenti regole tra le shell, così come di escape speciali per file con trattini, ecc.).
il globbing jolly della shell non funziona con un asterisco '*' su dotfile. Per elencare solo i file dot, usare:
ls .??*
Extra * non aggiunge il livello di profondità. Ma se ci provi
ls */*/*
- otterrai l'elenco delle sottocartelle delle sottocartelle nelle cartelle nella cartella corrente ...
*
aggiungeranno un livello di profondità.
bash
con l'opzione globstar, la shell korn e zsh. E forse altri, immagino. unix.stackexchange.com/a/62665/14831
La mia presa principale è che l'eco ** / *. Ext generalmente ...
Maggio o Maggio no: elenca un file .ext nella directory corrente
Maggio o Maggio no: includere i file. *. Ext
Generalmente preferirei che l'espressione glob sia '** /' e che può risultare in una stringa nulla (nessuna sottodirectory). Questo è il modo in cui converto le espressioni glob nell'input del programma. Certo, mi assicuro che ci sono commenti che spiegano questo in esempi di utilizzo.