Il risultato di ls *, ls ** e ls ***


86

So che usando il comando lselencherò tutte le directory. Ma cosa fa il ls *comando? L'ho usato ed elenca solo le directory. La stella di fronte lsindica quanto in profondità può elencare le directory?

Risposte:


155

lselenca 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 lsper i dettagli).

Se lsviene passato un argomento chiamato *, cercherà un file o una directory chiamata *nella directory corrente e lo elencherà come qualsiasi altro. lsnon 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 globsi 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, -le foo bar, *sarà ampliato dalla shell per due argomenti da passare a ls: -le 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 lscomando (che probabilmente verrà eseguito da /bin/lsuna ricerca di directory menzionate in $PATH) verranno passati questi 3 argomenti: "ls", "-l" e "foo bar".

Per inciso, in questo caso, lstratterà il primo (strettamente parlando secondo ) come un'opzione.

Ora, come ho detto, conchiglie diverse hanno operatori di globbing diversi. Qualche decennio fa, è stato zshintrodotto 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+), ksh93decise 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).

bashcopiato ksh93pochi 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.

yashaggiunto **nella versione 2.0 nel 2008, abilitato con l' extended-globopzione. La sua implementazione è più vicina a zshquella che **da sola non è speciale. Nella versione 2.15 (2009), ha aggiunto ***come in zshe 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, **/*.ccorrisponderà a/b/c.cma non a.c, mentre a**.ccorrisponderà a.ced ab/c/d.ce zsh' **/.*ad esempio deve essere scritto .* **/.*. Lì, ***è inteso come **seguito da *così lo stesso di **.

tcshha anche aggiunto globstarun'opzione in V6.17.01 (maggio 2010) e supporta sia **e ***à la zsh.

Quindi, in tcsh, bashe 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 tcshcon globstar, e lo stesso come *in bashe 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, cde pushde nomi di file che contengono il =carattere per awkper 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 $FIGNOREparametro inksh

Inoltre, in tutti i serbatoi ma csh, tcsh, fishe 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à lscon i due argomenti lse *. 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 directoryche è stato conosciuto per far pensare alle persone che in lsrealtà stava espandendo i globs.

Il problema è ancora peggiore in casi come:

rm -- *.[ab]

Se non c'è *.a*.bfile nella directory corrente, allora si potrebbe finire per l'eliminazione di un file chiamato *.[ab]per errore ( csh, tcsh, e zshpotrebbe segnalare un fiammifero di errore e non lo chiamerei rm(e fishnon 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 noglobo set -f(quest'ultimo non funziona zshse non in sh/ kshemulazione).


¹ 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)


22
Davvero un'ottima risposta!
Andrea Corbellini,

7
Un altro bell'esempio è 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.
njsg,

Continuo a dare +1, sono davvero felice di vedere Stephane Chazelas attivo qui su unix.stackexchange.com ! Grandi contributi, Stephane, come sempre!
Dimitre Radoulov,

1
Nel pesce, *.[ab]proverebbe a cancellare tutto finendo con .[ab]. [non è speciale nei pesci.
Konrad Borowski,

35

Il comando lspredefinito è 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.


17
Solo che in più * 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 *.
njsg,

12

Puoi demistificare l'intero processo digitando echoanziché lsprima, 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 bashcome shell - la maggior parte delle persone lo sono e diverse shell hanno comportamenti diversi. Se stai usando asho csho ksho 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 Downloadsdirectory 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.phpfile esistenti al livello base della public_htmldirectory di qualsiasi utente . O forse per essere più completo:

$ find /home/*/public_html/ -name wp-config.php

Questo troverà tutti i wp-config.phpfile nelle directory di qualsiasi utente public_htmlo in qualsiasi delle loro sottodirectory, ma funzionerà in modo più efficiente rispetto al semplice find /home/ -name wp-config.phpfatto che non esaminerà altro che le public_htmldirectory per ciascuno degli utenti.


1
"Questo presuppone che tu stia usando bashcome shell" ← e che la globstar non sia abilitata. shopt -s globstare riprovare ...
njsg

Un altro modo per demistificare è set -xche inizierà a stampare il comando "effettivo" eseguito ogni volta (spegnere con set +x).
ShreevatsaR,

10

In alcune shell, incluso bash 4.x con l' globstaropzione abilitata, **eseguirà un glob ricorsivo, decrescente le directory corrispondenti. Asterischi aggiuntivi non modificano ulteriormente questa operazione.


1
Tuttavia, come ho detto nella mia risposta, attenzione che, contrariamente a ksh93e zsh, bashattraversa i collegamenti simbolici nella ricorsione che è generalmente indesiderata.
Stéphane Chazelas,

Ciò è stato risolto nella bash 4.3
Stéphane Chazelas il

1

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 .??*


-1

Extra * non aggiunge il livello di profondità. Ma se ci provi

 ls */*/*

- otterrai l'elenco delle sottocartelle delle sottocartelle nelle cartelle nella cartella corrente ...


Sbagliato. A seconda della shell, gli extra *aggiungeranno un livello di profondità.
njsg,

quindi quale shell aggiungerà livello di profondità alle stelle extra?
VB9-UANIC,

Parecchi. Compreso GNU bashcon l'opzione globstar, la shell korn e zsh. E forse altri, immagino. unix.stackexchange.com/a/62665/14831
njsg

-1

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.

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.