Come elenco tutti i file in una directory tranne quelli con estensioni specificate?


28

Supponiamo di avere una cartella contenente .txt , .pdf e altri file. Vorrei elencare gli "altri" file (ovvero i file che non hanno le estensioni .txt o .pdf ). Hai qualche consiglio su come farlo?

So come elencare i file che non hanno una determinata estensione. Ad esempio, se voglio elencare tutti i file ad eccezione dei file .txt , quindi

find -not -iname "*.txt"

o

ls | grep -v '\.txt$' | column

sembra funzionare. Ma come posso elencare tutto tranne i file .txt o .pdf ? Sembra che ho bisogno di usare una sorta di "o" logico in findo grep.


2
Tieni presente che il comportamento di lsvs findvs globbing può differire per i dotfile nascosti.
jw013,

1
Un'altra cosa da tenere a mente: findattraverserà le sottodirectory, come una ricorsiva ls. Usa -maxdepth 1con findper farlo comportare più come ls.
jw013,

Quindi non ricorsivo, basta elencare i file nella directory corrente?
margherita,

Risposte:


28

Supponendo che uno abbia una versione appropriata di ls, questo è probabilmente il modo più semplice:

ls -I "*.txt" -I "*.pdf"

Se vuoi iterare in tutte le sottodirectory:

ls -I "*.txt" -I "*.pdf" -R

8
Le lsopzioni GNU non sono portatili.
bahamat,

4
lsnon appartiene comunque agli script portatili, quindi ho assunto che l'OP chiedesse solo l'uso interattivo.
jw013,

1
Perché non è portatile? Cosa dovrei usare allora?
Freedo il

28

Trova supporti -o

find . ! '(' -name '*.txt' -o -name '*.pdf' ')'

È necessaria la parentesi per rendere corretta la precedenza. Trova fa un sacco di cose; Suggerisco di leggere la sua manpage.

Puoi anche fare un o in grep(ma in realtà, non dovresti analizzare l'output dils )

ls | grep -Ev '\.(txt|pdf)$' | column

1
Grazie! Perché non dovrei analizzare l'output di ls?
Andrew,

6
@Andrew prima, perché è fragile (considera un nome di file con una nuova riga — sì, è un nome di file valido — trova's -print0 / -exec / -delete / etc. Evita quel problema); secondo, perché di solito esiste un modo più semplice.
derobert,

Oltre alla findmanpage, raccomando vivamente gli articoli di Unix Power Tools su find, come docstore.mik.ua/orelly/unix3/upt/ch09_06.htm e docstore.mik.ua/orelly/unix3/upt/ch09_12.htm
Wildcard il

Solo per aiutare a decodificare l'affermazione per gli umani:find . NOT ( *.txt OR *.pdf )
wisbucky

12

Con il bashglobbing esteso (accendere con shopt -s extglob), il glob !(*.txt|*.pdf)dovrebbe funzionare. È possibile passare questo glob direttamente a qualsiasi comando che accetta argomenti sui file, incluso ma non limitato a ls.


1
+1 ma se hai delle sottodirectory, anche i loro contenuti verranno elencati; usare -dper evitare che:ls -d !(*.txt|*.pdf)
legends2k

Grazie, stavo cercando proprio per la sintassi di accettare più file, questo si adatterebbe bene qui stackoverflow.com/questions/216995/...
Freedo

6

In zshcon extendedglob:

print -rl -- *~*.(txt|pdf)

o

print -rl -- ^*.(txt|pdf)

O con kshglob(sì, questo è ksh globbing non "bash extended globbing"):

print -rl -- !(*.txt|*.pdf)

Ricorda però che quelli escludono anche i file punto.

ksh93 ha la funzione FIGNORE(mis):

FIGNORE='@(.|..|*.txt|*.pdf)'
printf '%s\n' *


3

Come suggerito da derobert, la soluzione migliore è usare find. Tuttavia, è possibile utilizzare il risultato in una pipeline con altri comandi.

GNU (e alcuni BSD) findsupportano il -print0predicato che gli dice di stampare il nome del file terminato da un carattere NUL , il cui carattere non è consentito all'interno di un nome file e garantisce che non ci sarà una collisione. È possibile indicare ad altri comandi di utilizzare NUL come delimitatore di input.

Il più importante dei quali è GNU xargs, che esegue il comando specificato e gli passa l'elenco dei file come argomenti della riga di comando. Si desidera eseguire xargs -r0insieme a find's -print0Ad esempio:

find . -type f ! \( -name \*.pdf -o -name \*.txt \) -print0 | xargs -r0 ls -ld

Questo stampa in modo sicuro un lungo elenco di directory di tutti i file pdf e txt , inclusi quelli con spazi o caratteri non stampabili nel nome.

Puoi anche usarlo con GNU tarcome segue:

tar -zcf myarchive.tar.gz --null --files-from <(
  find . -type f ! -name \*.tar.gz -print0)

Questo crea un file tar.gz di tutti i file i cui nomi non finiscono in .tar.gz

rsyncaccetta anche file delimitati da null con il -0parametro, così come molti altri. Ma xargsè la colla che userai di solito per questo tipo di scopo. O quella o findla -execcaratteristica.


L' taresempio di comando è valido. Per la maggior parte degli scopi, tuttavia, -execè una soluzione migliore.
Wildcard il

1

Se non hai una sottodirectory

ls !(*.pdf|*.txt)

dovrebbe funzionare anche!

Ma

ls -I "*.pdf" -I "*.txt"

è il modo comune.


0

Come complemento, se si utilizza una shell compatibile con bash, è possibile utilizzare la variabile GLOBIGNORE per escludere i risultati dalla corrispondenza dei motivi. Dall'uomo:

   GLOBIGNORE
          A colon-separated list of patterns defining the set of filenames
          to be ignored by pathname expansion.  If a filename matched by a
          pathname  expansion  pattern also matches one of the patterns in
          GLOBIGNORE, it is removed from the list of matches.

Nel tuo caso particolare:

sh$ (GLOBIGNORE='*.pdf:*.txt'; ls -d *)

Nota che eseguo quel comando come sotto-shell (usando la parentesi) per non alterare la variabile d'ambiente GLOBIGNORE della mia shell interattiva.

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.