perché ls -d elenca anche i file e dove è documentato?


48
  • quando lo si specifica ls --directory a*dovrebbe elencare solo le directory che iniziano cona*
  • MA elenca i file E le directory che iniziano con a

Domande :

  • dove posso trovare un po 'di documentazione su questo, oltre a mane infodove penso di aver guardato a fondo?
  • funziona solo in BASH?


5
echo a*elencherà anche i file che iniziano con a(se presenti). Giusto per chiarire che non sta lsfacendo questo, ma il bash.
ash108,

Risposte:


89

La sintassi a*e *a*viene implementata dalla shell, non dal lscomando.

Quando si digita

ls a*

al prompt della shell, la shell si espande a*in un elenco di tutti i file esistenti nella directory corrente i cui nomi iniziano con a. Ad esempio, potrebbe espandersi a*nella sequenza a1 a2 a3e passare quelli come argomenti a ls. Il lscomando stesso non vede mai il *personaggio; si vede solo i tre argomenti a1, a2e a3.

Ai fini dell'espansione dei caratteri jolly, "file" si riferisce a tutte le entità nella directory corrente. Ad esempio, a1potrebbe essere un file normale, a2potrebbe essere una directory e a3potrebbe essere un collegamento simbolico. Hanno tutti voci di directory e l'espansione jolly della shell non interessa a quale tipo di entità si riferiscono quelle voci.

Praticamente tutte le shell che si possono incontrare (bash, sh, ksh, zsh, csh, tcsh, ...) implementano i caratteri jolly. I dettagli possono variare, ma la sintassi di base della *corrispondenza di zero o più caratteri e la ?corrispondenza di ogni singolo carattere è ragionevolmente coerente.

Per bash in particolare, questo è documentato nella sezione "Espansione nome file" del manuale bash; eseguire info bashe cercare "Espansione nome file" o vedere qui .

Il fatto che ciò avvenga con la shell, e non con i singoli comandi, ha alcune conseguenze interessanti (e talvolta sorprendenti). La cosa migliore è che la gestione dei caratteri jolly è coerente per (quasi) tutti i comandi; se la shell non lo avesse fatto, inevitabilmente alcuni comandi non si sarebbero disturbati, e altri lo avrebbero fatto in modi leggermente diversi che l'autore pensava fosse "migliore". (Penso che la shell dei comandi di Windows abbia questo problema, ma non ho abbastanza familiarità con esso per commentare ulteriormente.)

D'altra parte, è difficile scrivere un comando per rinominare più file. Se scrivi:

mv *.log *.log.bak

probabilmente fallirà, poiché *.log.bakviene espanso in base ai file già esistenti nella directory corrente. Ci sono comandi che fanno questo tipo di cose, ma devono usare la propria sintassi per specificare come i file devono essere rinominati. Alcuni comandi (come find) possono eseguire la propria espansione con caratteri jolly; devi citare gli argomenti per sopprimere l'espansione della shell:

find . -name '*.txt' -print

L'espansione jolly della shell si basa interamente sulla sintassi dell'argomento della riga di comando e sull'insieme dei file esistenti. Non può essere influenzato dal significato del comando. Ad esempio, se si desidera spostare tutti i .logfile nella directory principale, è possibile digitare:

mv *.log ..

Se dimentichi il ..:

mv *.log

e ci sono esattamente due .logfile nella directory corrente, si espanderà in:

mv one.log two.log

che rinominerà one.loge clobber two.log.

EDIT : E dopo 52 voti, un'accettazione e un badge Guru, forse dovrei effettivamente rispondere alla domanda nel titolo.

L' opzione -do non dice di elencare solo le directory. Gli dice di elencare le directory come se stesse, non i loro contenuti. Se si fornisce un nome di directory come argomento , per impostazione predefinita elencherà il contenuto della directory, poiché di solito è quello che ti interessa. L' opzione dice di elencare solo la directory stessa. Ciò può essere particolarmente utile se combinato con caratteri jolly. Se digiti:--directorylsls-d

ls -l a*

lsti darà un lungo elenco di ogni file il cui nome inizia con ae del contenuto di ogni directory il cui nome inizia con a. Se desideri solo un elenco di file e directory, una riga per ciascuno, puoi utilizzare:

ls -ld a*

che equivale a:

ls -l -d a*

Ricorda ancora che il lscomando non vede mai il *personaggio.

Per quanto riguarda dove questo è documentato, man lsti mostrerà la documentazione per il lscomando su qualsiasi sistema simile a Unix. Sulla maggior parte dei sistemi basati su Linux, il lscomando fa parte del pacchetto GNU coreutils; se avete la infodi comando, sia info lso info coreutils lsdovrebbe darvi una documentazione più definitivo e completo. Altri sistemi, come MacOS, possono utilizzare versioni diverse del lscomando e potrebbero non avere il infocomando; per tali sistemi, utilizzare man ls. E ls --helpmostrerà un messaggio di utilizzo relativamente breve (117 righe sul mio sistema) se stai usando l'implementazione di coreutils GNU.

E sì, anche gli esperti devono consultare la documentazione di tanto in tanto. Vedi anche questa barzelletta classica .


8
@Thomas: si a*espande in un elenco di tutti i file nella directory corrente i cui nomi iniziano con a.
Keith Thompson

2
@Thomas: O in qualunque directory tu specifichi:ls subdir/a*
Keith Thompson

1
Per vedere davvero il comando eseguito dopo l'espansione della shell, echoesso. Quindi, se vuoi sapere cosa sta succedendo quando lo fai ls a*, esegui primaecho ls a*
Carlos Campderrós

1
o semplicemente echo a*... la shell fa comunque l'espansione glob
Inutile

2
@sendmoreinfo: dipende dalla shell e dalle impostazioni. In csh e tcsh, un'espansione glob non riuscita è un errore. In bash, shopt -s failglobprovoca lo stesso comportamento. L'impostazione nullglobma non failglobcausa, ad esempio, *nosuchfile*l'espansione in una stringa vuota.
Keith Thompson,

27

Vedi la risposta di Keith Thompson; ma per spiegare perché ls --directory a*mostra file e directory: L' --directoryopzione non elimina i file non di directory. Invece, elenca le directory in quanto tali, mentre altrimenti elenca il loro contenuto. Esempio:

$ mkdir foo
$ touch foo/bar
$ ls foo
bar
$ ls --directory foo
foo

3
quell'esempio è più avvincente con l' -Fopzione
glenn jackman,

6

Per essere molto esplicito, è documentato nella pagina del manuale ls (1) :

-d, --directory elenca le voci della directory anziché i contenuti e non fa riferimento a collegamenti simbolici

per essere onesti, "le voci anziché i contenuti" potrebbero probabilmente essere più esplicative:

Se FILE è una directory, mostra la voce della directory stessa invece di elencare il contenuto di quella directory. Se FILE è un collegamento simbolico, mostra la voce di collegamento stessa invece del file a cui punta il collegamento.


Per essere pedanti, mentre l'opzione -d può essere spiegata (se tersamente) nella pagina man, l'espansione degli argomenti e il carattere jolly non sono documentati nella pagina man ls poiché sono fatti dalla shell. Se disattivi l'espansione del nome file nella shell, "ls a *" ti mostrerà solo un file che è letteralmente chiamato "a *".
Johnny,

Per essere pedanti, mentre l'espansione della shell ha risposto ad altri intervistati, nessuno di loro affronta la scarsa spiegazione e come potrebbe essere frainteso. Se ti piacerebbe che ripetessi ciò che era già stato ben detto, per favore sii più diretto.
msw

4

globbing

Come è stato spiegato, l'espansione di *(e simili espansioni) è chiamata globbing nel gergo di Unix, ed è di solito una caratteristica del processore dei comandi (noto come "shell" nel linguaggio Unix). Quindi il globbing può essere usato anche in molti altri luoghi; digitare man 7 globnella shell di una classica distribuzione Linux (o vedere questo ) per ulteriori informazioni sul globbing.

All'inizio di Unix, globera effettivamente implementato da un programma separato chiamato /etc/glob(vedi pagina 10 di questo vecchio manuale UNIX per la documentazione per questo). Oggi è una routine di codice fornita dalle librerie di codici ed è comunemente usata dalle shell. Fonte : Wikipedia .

Elenchi

Per quanto riguarda il perché ls -delenca i file e le directory ...

La lspagina man spiega perché questo accade, ma con una spiegazione molto concisa. Quindi, ecco un tentativo di spiegazione estesa:

Per impostazione predefinita lselenca il contenuto delle directory quando viene loro assegnato il nome e farà la stessa cosa per i collegamenti simbolici alle directory. L' -dopzione significa "quando vengono dati i nomi della directory (e)" (che può anche essere data implicitamente da globbing) , mostra solo il nome_s della directory (e), ma non il loro contenuto. Allo stesso modo, quando fornito con il nome (esplicito o implicito ) dei collegamenti simbolici alle directory , mostra il nome del file del collegamento simbolico, non il contenuto della directory a cui fa riferimento.

L' -dopzione non ha nulla a che fare, per quanto posso dire, con quali elementi sono elencati; questo può essere fatto (fonte: qui ) con find, in questo modo: find . -maxdepth 1 -type d. Non sono sicuro che ci sia un buon modo per farlo solo con GNU ls. Ecco alcuni esempi di come usare il findcomando.

Quindi per riassumere: per impostazione predefinita lsmostra il contenuto delle directory quando viene assegnato il nome del percorso. -dcambia questo comportamento, mostrando solo il nome della directory stessa, come si farebbe per un file standard.


3

La documentazione non dice che elenca solo le voci della directory ma piuttosto quando lsriceve il nome della directory elenca la voce dir invece del suo contenuto. Il modo migliore per capire è con l'esempio:

> {ice} ~ :10:47 % ls -l / 
total 97
drwxr-xr-x   2 root root  4096 May  3 00:27 bin
drwxr-xr-x   4 root root  1024 May  3 14:17 boot
drwxr-xr-x   2 root root  4096 Apr 29 13:44 cdrom
drwxr-xr-x  18 root root  4420 May  9 09:58 dev
...
lrwxrwxrwx   1 root root    33 May  3 14:16 vmlinuz -> boot/vmlinuz-3.9.0-030900-generic
lrwxrwxrwx   1 root root    29 May  3 11:07 vmlinuz.old -> boot/vmlinuz-3.8.0-19-generic
> {ice} ~ :10:47 % ls -ld /
drwxr-xr-x 25 root root 4096 May  3 14:16 /

2

La documentazione fa parte della shell . In particolare la shell esegue varie espansioni e sostituzioni in un ordine particolare prima di eseguire un comando.

La sequenza di espansioni di parole per una shell compatibile con Bourne è

  1. Espansione Tilde
  2. Espansione dei parametri
  3. Sostituzione comando
  4. Espansione aritmetica
  5. Divisione del campo
  6. Espansione percorso
  7. Rimozione preventivo

Quindi, il lscomando non vede nemmeno i *caratteri, gli argomenti sono già espansi con tutti i file che corrispondono al a*modello glob. Questo è diverso da Windows, dove ogni comando che richiede il globbing del nome file deve implementare questa funzione da solo.


1

La parola chiave che ti serve ( man bash) è "Espansione percorso".


3
più come "Pathname Expansion" o "Filename Generation". Relativo alla "corrispondenza del modello", ma non è lo stesso.
Stéphane Chazelas,

@StephaneChazelas In effetti, ma "pattern matching" è una sottosezione di "espansione del nome percorso" nella pagina man mentre "Generazione nome file" non si verifica affatto lì (solo nel documento informativo).
Hauke ​​Laging
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.