Verifica dallo script di shell se una directory contiene file

Da uno script di shell, come posso verificare se una directory contiene file?

Qualcosa di simile a questo

if [ -e /some/dir/* ]; then echo "huzzah"; fi; 

ma che funziona se la directory contiene uno o più file (quello sopra funziona solo con esattamente 0 o 1 file).

Le soluzioni finora usano ls . Ecco una soluzione bash:

 #!/bin/bash shopt -s nullglob dotglob # To include hidden files files=(/some/dir/*) if [ ${#files[@]} -gt 0 ]; then echo "huzzah"; fi 

Tre migliori trucchi


shopt -s nullglob dotglob; f=your/dir/*; ((${#f}))

Questo trucco è al 100% bash e invoca (genera) una sotto-shell. L’idea è di Bruno De Fraine e migliorata dal commento di teambob .

 files=$(shopt -s nullglob dotglob; echo your/dir/*) if (( ${#files} )) then echo "contains files" else echo "empty (or does not exist or is a file)" fi 

Nota: nessuna differenza tra una directory vuota e una non esistente (e anche quando il percorso fornito è un file).

C’è un’alternativa simile e maggiori dettagli (e altri esempi) sulle FAQ “ufficiali” per il canale IRC #bash :

 if (shopt -s nullglob dotglob; f=(*); ((${#f[@]}))) then echo "contains files" else echo "empty (or does not exist, or is a file)" fi 

[ -n "$(ls -A your/dir)" ]

Questo trucco è ispirato all’articolo di nixCraft pubblicato nel 2007. Aggiungi 2>/dev/null per sopprimere l’errore di output "No such file or directory" .
Vedi anche la risposta di Andrew Taylor (2008) e la risposta di gr8can8dian (2011).

 if [ -n "$(ls -A your/dir 2>/dev/null)" ] then echo "contains files (or is a file)" else echo "empty (or does not exist)" fi 

o la versione del bashismo a una riga:

 [[ $(ls -A your/dir) ]] && echo "contains files" || echo "empty" 

Nota: ls restituisce $?=2 quando la directory non esiste. Ma nessuna differenza tra un file e una directory vuota.


[ -n "$(find your/dir -prune -empty)" ]

Quest’ultimo trucco è ispirato alla risposta di -maxdepth 0 dove -maxdepth 0 è sostituito da -prune e migliorato dal commento di phils .

 if [ -n "$(find your/dir -prune -empty 2>/dev/null)" ] then echo "empty (directory or file)" else echo "contains files (or does not exist)" fi 

una variazione usando -type d :

 if [ -n "$(find your/dir -prune -empty -type d 2>/dev/null)" ] then echo "empty directory" else echo "contains files (or does not exist or is not a directory)" fi 

Spiegazione:

  • find -prune è simile a find -maxdepth 0 utilizzando meno caratteri
  • find -empty stampa le directory e i file vuoti
  • find -type d stampa solo le directory

Nota: puoi anche sostituire [ -n "$(find your/dir -prune -empty)" ] solo dalla versione abbreviata di seguito:

 if [ `find your/dir -prune -empty 2>/dev/null` ] then echo "empty (directory or file)" else echo "contains files (or does not exist)" fi 

Questo ultimo codice funziona per la maggior parte dei casi, ma ricorda che i percorsi dannosi potrebbero esprimere un comando …

Che ne dici di quanto segue:

 if find /some/dir/ -maxdepth 0 -empty | read v; then echo "Empty dir"; fi 

In questo modo non è necessario generare un elenco completo dei contenuti della directory. La read è sia per scartare l’output e rendere l’espressione valutata su true solo quando qualcosa viene letto (cioè /some/dir/ viene trovato vuoto da find ).

Provare:

 if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi 
 # Works on hidden files, directories and regular files ### isEmpty() # This function takes one parameter: # $1 is the directory to check # Echoes "huzzah" if the directory has files function isEmpty(){ if [ "$(ls -A $1)" ]; then echo "huzzah" else echo "has no files" fi } 

Abbi cura delle directory con molti file! Potrebbe volerci un po ‘di tempo per valutare il comando ls .

IMO la soluzione migliore è quella che utilizza

 find /some/dir/ -maxdepth 0 -empty 
 DIR="/some/dir" if [ "$(ls -A $DIR)" ]; then echo 'There is something alive in here' fi 

Potresti confrontare l’output di questo?

  ls -A /some/dir | wc -l 
 # Controlla se una directory contiene file non nascosti.
 #
 # usage: if isempty "$ HOME";  quindi eco "Welcome home";  fi
 #
 è vuoto() {
     per _ief in $ 1 / *;  fare
         if [-e "$ _ief"];  poi
             ritorno 1
         fi
     fatto
     ritorno 0
 }

Alcune note di implementazione:

  • Il ciclo for evita una chiamata a un processo ls esterno. Legge ancora tutte le voci della directory una volta. Questo può essere ottimizzato solo scrivendo un programma C che usa readdir () esplicitamente.
  • Il test -e all’interno del loop cattura il caso di una directory vuota, nel qual caso alla variabile _ief verrebbe assegnato il valore “somedir / *”. Solo se il file esiste, la funzione restituirà “non vuoto”
  • Questa funzione funzionerà in tutte le implementazioni POSIX. Ma sappi che Solaris / bin / sh non rientra in quella categoria. L’implementazione del test non supporta il flag -e .

Questa potrebbe essere una risposta molto tardiva, ma qui c’è una soluzione che funziona. Questa riga riconosce solo l’esistenza di file! Non ti darà un falso positivo se esistono le directory.

 if find /path/to/check/* -maxdepth 0 -type f | read then echo "Files Exist" fi 

Questo mi dice se la directory è vuota o, in caso contrario, il numero di file che contiene.

 directory="/some/dir" number_of_files=$(ls -A $directory | wc -l) if [ "$number_of_files" == "0" ]; then echo "directory $directory is empty" else echo "directory $directory contains $number_of_files files" fi 
 dir_is_empty() { [ "${1##*/}" = "*" ] } if dir_is_empty /some/dir/* ; then echo "huzzah" fi 

Supponiamo che tu non abbia un file di nome * in /any/dir/you/check , che dovrebbe funzionare su bash posh busybox sh e zsh ma (per zsh) richiede un unsetopt nomatch .

Le prestazioni dovrebbero essere paragonabili a quelle che usano * (glob), immagino che sarà lento nelle directory con molti nodes (il mio /usr/bin con più di 3000 file non è così lento), userà almeno una memoria sufficiente per allocare tutte le directory / nomi di file (e altro) dato che sono tutti passati (risolti) alla funzione come argomenti, alcune shell hanno probabilmente dei limiti sul numero di argomenti e / o sulla lunghezza degli argomenti.

Un modo veloce e portatile O (1) a zero risorse per controllare se una directory è vuota sarebbe bello avere.

aggiornare

La versione precedente non tiene conto di file / dir nascosti, nel caso sia necessario un po ‘più di test, come l’ is_empty dai is_empty di sh (POSIX shell) di Rich :

 is_empty () ( cd "$1" set -- .[!.]* ; test -f "$1" && return 1 set -- ..?* ; test -f "$1" && return 1 set -- * ; test -f "$1" && return 1 return 0 ) 

Ma, invece, sto pensando a qualcosa del genere:

 dir_is_empty() { [ "$(find "$1" -name "?*" | dd bs=$((${#1}+3)) count=1 2>/dev/null)" = "$1" ] } 

Alcune preoccupazioni riguardo le differenze di slash finali dall’argomento e l’output di find quando la dir è vuota, e le newline finali (ma dovrebbe essere facile da gestire), purtroppo sul mio busybox sh mostra quello che probabilmente è un bug sul find -> dd pipe con l’output troncato casualmente (se ho usato cat l’output è sempre lo stesso, sembra essere dd con il count degli argomenti).

Piccola variazione della risposta di Bruno :

 files=$(ls -1 /some/dir| wc -l) if [ $files -gt 0 ] then echo "Contains files" else echo "Empty" fi 

Per me funziona

ZSH

So che la domanda è stata contrassegnata per bash; ma, solo per riferimento, per gli utenti zsh :

Prova per directory non vuota

Per verificare se foo non è vuoto:

 $ for i in foo(NF) ; do ... ; done 

dove, se foo è non vuoto, verrà eseguito il codice nel blocco for .

Verifica la directory vuota

Per verificare se foo è vuoto:

 $ for i in foo(N/^F) ; do ... ; done 

dove, se foo è vuoto, verrà eseguito il codice nel blocco for .

Gli appunti

Non abbiamo bisogno di citare la directory di cui sopra, ma possiamo farlo se abbiamo bisogno di:

 $ for i in 'some directory!'(NF) ; do ... ; done 

Possiamo anche testare più di un object, anche se non è una directory:

 $ mkdir X # empty directory $ touch f # regular file $ for i in X(N/^F) f(N/^F) ; do echo $i ; done # echo empty directories X 

Tutto ciò che non è una directory verrà semplicemente ignorato.

extra

Dal momento che siamo globbing, possiamo usare qualsiasi glob (o espansione brace):

 $ mkdir X X1 X2 Y Y1 Y2 Z $ touch Xf # create regular file $ touch X1/f # directory X1 is not empty $ touch Y1/.f # directory Y1 is not empty $ ls -F # list all objects X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/ $ for i in {X,Y}*(N/^F); do printf "$i "; done; echo # print empty directories X X2 Y Y2 

Possiamo anche esaminare oggetti che sono posizionati in una matrice. Con le directory come sopra, ad esempio:

 $ ls -F # list all objects X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/ $ arr=(*) # place objects into array "arr" $ for i in ${^arr}(N/^F); do printf "$i "; done; echo X X2 Y Y2 Z 

Pertanto, possiamo testare oggetti che potrebbero già essere impostati in un parametro array.

Si noti che il codice nel blocco for è, ovviamente, eseguito su ogni directory a sua volta. Se questo non è desiderabile, puoi semplicemente popolare un parametro dell’array e poi operare su quel parametro:

 $ for i in *(NF) ; do full_directories+=($i) ; done $ do_something $full_directories 

Spiegazione

Per gli utenti zsh esiste il qualificatore di livello (F) (vedi man zshexpn ), che corrisponde alle directory “complete” (non vuote):

 $ mkdir XY $ touch Y/.f # Y is now not empty $ touch f # create a regular file $ ls -dF * # list everything in the current directory f X/ Y/ $ ls -dF *(F) # will list only "full" directories Y/ 

Il qualificatore (F) elenca gli oggetti che corrispondono: è una directory AND non vuota. Quindi, (^F) corrisponde: non una directory O è vuota. Quindi, (^F) da solo elencherebbe anche file regolari, per esempio. Quindi, come spiegato nella pagina man zshexp , abbiamo anche bisogno del qualificatore glob (/) , che elenca solo le directory:

 $ mkdir XYZ $ touch X/f Y/.f # directories X and Y now not empty $ for i in *(/^F) ; do echo $i ; done Z 

Pertanto, per verificare se una determinata directory è vuota, puoi quindi eseguire:

 $ mkdir X $ for i in X(/^F) ; do echo $i ; done ; echo "finished" X finished 

e solo per essere sicuro che una directory non vuota non sarebbe stata catturata:

 $ mkdir Y $ touch Y/.f $ for i in Y(/^F) ; do echo $i ; done ; echo "finished" zsh: no matches found: Y(/^F) finished 

Oops! Poiché Y non è vuoto, zsh non trova corrispondenze per (/^F) (“directory vuote”) e quindi invia un messaggio di errore che dice che non sono state trovate corrispondenze per il glob. Pertanto, è necessario sopprimere questi possibili messaggi di errore con il qualificatore (N) glob:

 $ mkdir Y $ touch Y/.f $ for i in Y(N/^F) ; do echo $i ; done ; echo "finished" finished 

Quindi, per le directory non vuote abbiamo bisogno del qualificatore (N/^F) , che puoi leggere come: “non avvisarmi dei guasti, directory non piene”.

Allo stesso modo, per le directory vuote abbiamo bisogno del qualificatore (NF) , che possiamo anche leggere come: “non avvisarmi dei guasti, delle directory complete”.

 if ls /some/dir/* >/dev/null 2>&1 ; then echo "huzzah"; fi; 

Sono sorpreso che la guida di Wooledge sulle directory vuote non sia stata menzionata. Questa guida, e tutta la lana veramente, è una lettura obbligata per le domande sul tipo di shell.

Da notare da quella pagina:

Non cercare mai di analizzare l’output di ls. Persino ls -A soluzioni possono rompersi (ad esempio su HP-UX, se sei root, ls -A fa l’esatto opposto di quello che fa se non sei root – e no, non riesco a inventare qualcosa che incredibilmente stupido).

In effetti, si potrebbe desiderare di evitare del tutto la domanda diretta. Di solito le persone vogliono sapere se una directory è vuota perché vogliono fare qualcosa che coinvolga i file in essa contenuti, ecc. Guarda alla domanda più ampia. Ad esempio, uno di questi esempi basati sulla ricerca potrebbe essere una soluzione appropriata:

  # Bourne find "$somedir" -type f -exec echo Found unexpected file {} \; find "$somedir" -maxdepth 0 -empty -exec echo {} is empty. \; # GNU/BSD find "$somedir" -type d -empty -exec cp /my/configfile {} \; # GNU/BSD 

Più comunemente, tutto ciò che è veramente necessario è qualcosa del genere:

  # Bourne for f in ./*.mpg; do test -f "$f" || continue mympgviewer "$f" done 

In altre parole, la persona che ha posto la domanda potrebbe aver pensato che fosse necessario un test esplicito di directory vuote per evitare un messaggio di errore come mympgviewer: ./*.mpg: non esiste tale file o directory quando in effetti non è richiesto alcun test di questo tipo.

Finora non ho visto una risposta che utilizza grep, che a mio avviso darebbe una risposta più semplice (con non troppi simboli strani!). Ecco come controllerei se esistono dei file nella directory usando la shell di Bourne:

questo restituisce il numero di file in una directory:

 ls -l  | egrep -c "^-" 

è ansible compilare il percorso della directory in cui è scritta la directory. La prima metà della pipa assicura che il primo carattere dell’output sia “-” per ogni file. egrep quindi conta il numero di righe che iniziano con quel simbolo usando le espressioni regolari. ora tutto ciò che devi fare è memorizzare il numero che ottieni e confrontarlo usando backquote come:

  #!/bin/sh fileNum=`ls -l  | egrep -c "^-"` if [ $fileNum == x ] then #do what you want to do fi 

x è una variabile di tua scelta.

Mescolando cose di prugna e ultime risposte, ci sono riuscito

 find "$some_dir" -prune -empty -type d | read && echo empty || echo "not empty" 

che funziona anche per i percorsi con spazi

Risposta semplice con bash :

 if [[ $(ls /some/dir/) ]]; then echo "huzzah"; fi; 

Vorrei andare a find :

 if [ -z "$(find $dir -maxdepth 1 -type f)" ]; then echo "$dir has NO files" else echo "$dir has files" 

Questo controlla l’output di cercare solo i file nella directory, senza passare attraverso le sottodirectory. Quindi controlla l’output usando l’opzione -z presa dal man test :

  -z STRING the length of STRING is zero 

Vedi alcuni risultati:

 $ mkdir aaa $ dir="aaa" 

Dir vuoto:

 $ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty" empty 

Basta dirs:

 $ mkdir aaa/bbb $ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty" empty 

Un file nella directory:

 $ touch aaa/myfile $ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty" $ rm aaa/myfile 

Un file in una sottodirectory:

 $ touch aaa/bbb/another_file $ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty" empty 

Prova con il comando find. Specificare la directory codificata o come argomento. Quindi avviare find per cercare tutti i file all’interno della directory. Controlla se il reso di ritrovamento è nullo. Eco i dati di trovare

 #!/bin/bash _DIR="/home/user/test/" #_DIR=$1 _FIND=$(find $_DIR -type f ) if [ -n "$_FIND" ] then echo -e "$_DIR contains files or subdirs with files \n\n " echo "$_FIND" else echo "empty (or does not exist)" fi 

Con qualche soluzione, ho trovato un modo semplice per scoprire se ci sono file in una directory. Questo può estendersi di più con i comandi grep per controllare specificatamente file .xml o .txt, ecc. Es: ls /some/dir | grep xml | wc -l | grep -w "0" ls /some/dir | grep xml | wc -l | grep -w "0"

 #!/bin/bash if ([ $(ls /some/dir | wc -l | grep -w "0") ]) then echo 'No files' else echo 'Found files' fi 

Non mi piace il ls - A soluzioni pubblicate. Molto probabilmente si desidera verificare se la directory è vuota perché non si desidera eliminarla. Quanto segue lo fa. Se invece desideri semplicemente registrare un file vuoto, sicuramente cancellarlo e ricrearlo è più veloce, quindi elencare i file possibilmente infiniti?

Questo dovrebbe funzionare …

 if ! rmdir ${target} then echo "not empty" else echo "empty" mkdir ${target} fi 

per testare una directory di destinazione specifica

 if [ -d $target_dir ]; then ls_contents=$(ls -1 $target_dir | xargs); if [ ! -z "$ls_contents" -a "$ls_contents" != "" ]; then echo "is not empty"; else echo "is empty"; fi; else echo "directory does not exist"; fi; 

Funziona bene per me questo (quando dir esistono):

 some_dir="/some/dir with whitespace & other characters/" if find "`echo "$some_dir"`" -maxdepth 0 -empty | read v; then echo "Empty dir"; fi 

Con controllo completo:

 if [ -d "$some_dir" ]; then if find "`echo "$some_dir"`" -maxdepth 0 -empty | read v; then echo "Empty dir"; else "Dir is NOT empty" fi fi