So di usare il comando ls
elencherà tutte le directory. Ma cosa significa ls *
comando fare? L'ho usato e elenca solo le directory. La stella davanti a ls
significa quanto in profondità elencherà le directory?
Risposta accettata:
ls
elenca i file e il contenuto delle directory che viene passato come argomenti e, se non viene fornito alcun argomento, elenca la directory corrente. Può anche essere passato un certo numero 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 ed elencarlo come qualsiasi altro. ls
non tratta il *
carattere in modo diverso da qualsiasi altro.
Tuttavia, se ls *
è un guscio riga di comando, ovvero codice nel linguaggio di una shell Unix , quindi la shell espanderà quel *
secondo il suo globbing (indicato anche come Generazione di nomi di file o Espansione nome file/percorso ) regole.
Sebbene shell diverse supportino diversi operatori di globbing, la maggior parte di esse concorda sul più semplice *
. *
come pattern significa un numero qualsiasi di caratteri, quindi *
come glob
si espanderà all'elenco dei file nelle directory correnti che corrispondono a quel modello. C'è un'eccezione, tuttavia, che un punto iniziale (.
) il carattere 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 lessicale).
Ad esempio, se la directory corrente contiene i file chiamati .
, ..
, .foo
, -l
e foo bar
, *
verrà espanso dalla shell a due argomenti da passare a ls
:-l
e foo bar
, quindi sarà come se avessi 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, il ls
comando (che probabilmente verrà eseguito da /bin/ls
da una ricerca di directory menzionate in $PATH
) verranno passati quei 3 argomenti:“ls”, “-l” e “foo bar”.
Per inciso, in questo caso, ls
tratterà il primo (in senso stretto secondo ) uno come opzione.
Ora, come ho detto, shell diverse hanno operatori di globbing diversi. Alcuni decenni fa, zsh
introdotto il **/
operator¹ che significa corrispondere a qualsiasi livello di sottodirectory, abbreviazione di (*/)#
e ***/
che è lo stesso tranne per il fatto che segue i collegamenti simbolici durante la discesa delle directory.
Alcuni anni fa (luglio 2003, ksh93o+
), ksh93
ha deciso di copiare quel comportamento ma ha deciso di renderlo facoltativo e ha coperto solo il **
caso (non ***
). Inoltre, mentre **
da solo non era speciale in zsh
² (significava proprio come *
come in altre shell tradizionali da **
indica un numero qualsiasi di caratteri seguito da un numero qualsiasi di caratteri), in ksh93, **
significava lo stesso di **/*
(quindi qualsiasi file o directory al di sotto di quello corrente (esclusi i file nascosti)³.
bash
copiato ksh93
qualche anno dopo (febbraio 2009, bash 4.0), con la stessa sintassi ma una sfortunata differenza:**
di bash era come zsh
's ***
, ovvero seguiva i collegamenti simbolici quando ricorreva nelle sottodirectory che generalmente non è quello che vuoi che faccia e può avere cattivi effetti collaterali. È stato in parte risolto in bash-4.3 in quanto i collegamenti simbolici erano ancora seguiti, ma la ricorsione si è fermata lì. È stato completamente risolto in 5.0.
yash
aggiunto **
nella versione 2.0 nel 2008, abilitato con il extended-glob
opzione. La sua implementazione è più vicina a zsh
è in quel **
da solo 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 globale (come in **/*(D)
) prenderà in considerazione i file e le directory nascosti, ma se vuoi solo attraversare le directory nascoste ma non espandere i file nascosti, è necessario ((*|.*)/)#*
o **/[^.]*(D)
).
Il guscio di pesce supporta anche **
. Come la versione precedente di bash
, segue i collegamenti simbolici quando discende l'albero delle directory. In quella shell però **/*
non è uguale a **
. **
è più un'estensione di *
che può estendersi su più directory. In fish
, **/*.c
corrisponderà a a/b/c.c
ma non a.c
, mentre a**.c
corrisponderà a a.c
e ab/c/d.c
e zsh
's **/.*
per esempio deve essere scritto .* **/.*
. Ecco, ***
è inteso come **
seguito da *
quindi lo stesso di **
.
tcsh
aggiunto anche un globstar
opzione in V6.17.01 (maggio 2010) e supporta entrambi **
e ***
alla zsh
.
Quindi in tcsh
, bash
e ksh93
, (quando l'opzione corrispondente è abilitata (globstar
)) o fish
, **
espande tutti i file e le directory sotto quello corrente e ***
è uguale a **
per fish
, un collegamento simbolico che attraversa **
per tcsh
con globstar
e lo stesso di *
in bash
e ksh93
(sebbene non sia impossibile che le versioni future di quelle shell attraversino anche i collegamenti simbolici).
Sopra, avrai notato la necessità di assicurarti che nessuna delle espansioni venga interpretata come un'opzione. Per questo, faresti:
ls -- *
Oppure:
ls ./*
Ci sono alcuni comandi (non importa per ls
) dove è preferibile la seconda poiché anche con il --
alcuni nomi di file possono essere trattati in modo speciale. È il caso di -
per la maggior parte delle utilità di testo, cd
e pushd
e nomi di file che contengono =
carattere per awk
per esempio. ./
anteposto 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 un numero di opzioni che influenzano il comportamento del globbing (come se i file dot vengono ignorati o meno, l'ordine di ordinamento, cosa fare se non c'è corrispondenza...), vedi anche il $FIGNORE
parametro in ksh
Inoltre, in ogni shell tranne csh
, tcsh
, fish
e zsh
, se il modello di globbing non corrisponde a nessun file, il modello viene passato come argomento non espanso che causa confusione e possibilmente bug. Ad esempio, se non ci sono file non nascosti nella directory corrente
ls *
In realtà chiamerà ls
con i due argomenti ls
e *
. E poiché non esiste alcun file, quindi nessuno si chiama *
in entrambi i casi vedrai un messaggio di errore da ls (non la shell) come:ls: cannot access *: No such file or directory
, che è noto per far pensare alla gente che fosse ls
in realtà stava espandendo i glob.
Il problema è ancora peggiore in casi come:
rm -- *.[ab]
Se non è presente *.a
né *.b
file nella directory corrente, potresti finire per eliminare un file chiamato *.[ab]
per errore (csh
, tcsh
e zsh
segnalerebbe una nessuna corrispondenza errore e non chiamerebbe rm
(e fish
non supporta il [...]
caratteri jolly)).
Se vuoi passare un *
letterale a ls
, devi citare quel *
carattere in qualche modo come in ls *
o ls '*'
o ls "*"
. Nelle shell simili a POSIX, il globbing può essere disabilitato del tutto usando set -o noglob
o set -f
(quest'ultimo non funziona in zsh
a meno che in sh
/ksh
emulazione).
.