it-swarm-eu.dev

Verifica dallo script Shell se una directory contiene file

Da uno script 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).

95
ionn

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
61
Bruno De Fraine

Tre migliori trucchi


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

Questo trucco è bash al 100% e invoca (spawn) una sub-shell. L'idea è da 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 più dettagli (e più esempi) sul 'ufficiale' FAQ per il canale #bash IRC :

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 dall'articolo di nixCraft pubblicato nel 2007. Aggiungi 2>/dev/null per sopprimere l'errore di output "No such file or directory".
Vedi anche Risposta di Andrew Taylor (2008) e gr8can8dian risposta (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 da la risposta di gravstar dove -maxdepth 0 è stato 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 variante che utilizza -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 ...

114
olibre

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. read è sia per scartare l'output sia per rendere l'espressione valutata su true solo quando qualcosa viene letto (ad esempio /some/dir/ è trovato vuoto da find).

47
mweerden

Provare:

if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi
19
Greg Hewgill
# 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
}
14
gr8can8dian

Fai attenzione alle 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
12
Gravstar
DIR="/some/dir"
if [ "$(ls -A $DIR)" ]; then
     echo 'There is something alive in here'
fi
9
Andrew Taylor

Potresti confrontare l'output di questo?

 ls -A /some/dir | wc -l
5
DGM
 # Controlla se una directory contiene file non nascosti .
 # 
 # Utilizzo: if isempty "$ HOME"; quindi echo "Welcome home"; fi 
 # 
 isempty () {
 per _ief in $ 1/*; fare
 if [-e "$ _ief"]; poi
 restituire 1 
 fi 
 fatto
 restituisce 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 usi esplicitamente readdir ().
  • Il test -e all'interno del ciclo 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 test non supporta il flag -e.
4
Roland Illig

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
3
Daishi

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
2
bitstreamer
dir_is_empty() {
   [ "${1##*/}" = "*" ]
}

if dir_is_empty /some/dir/* ; then
   echo "huzzah"
fi

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

Le performance dovrebbero essere paragonabili a qualsiasi ls che usa * (glob), credo che sarà lento nelle directory con molti nodi (il mio /usr/bin con 3000+ file non è andato così lento), userà almeno una memoria sufficiente per allocare tutti i dirs/nomi di file ( e altro) dato che sono tutti passati (risolti) alla funzione come argomenti, alcuni Shell hanno probabilmente dei limiti sul numero di argomenti e/o la lunghezza degli argomenti.

Un modo veloce portatile O(1) a zero risorse per verificare 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 il is_empty da i trucchi di Rich sh (POSIX Shell) :

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 alle differenze di slash finali dall'argomento e all'output di find quando la dir è vuota e alla fine di newline (ma dovrebbe essere facile da gestire), purtroppo sul mio busyboxsh mostra quello che probabilmente è un bug nella pipa find -> dd con l'output troncato in modo casuale (se ho usato cat l'output è sempre lo stesso, sembra essere dd con l'argomento count).

1
Alex

ZSH

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

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.

Prova per 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 foo sopra, ma possiamo farlo se abbiamo bisogno di:

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

Possiamo anche testare più di un oggetto, 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 ciò 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 è disponibile il qualificatore glob (F) (vedere man zshexpn), che corrisponde alle directory "complete" (non vuote):

$ mkdir X Y
$ 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 OR è vuota. Pertanto, (^F) solo elencerebbe anche i file regolari, ad esempio. Quindi, come spiegato nella pagina man zshexp, abbiamo anche bisogno del qualificatore glob (/), che elenca solo le directory:

$ mkdir X Y Z
$ 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 venisse 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 sputa 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 glob (N):

$ 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 che non sono complete".

Allo stesso modo, per le directory vuote abbiamo bisogno del qualificatore (NF), che possiamo anche leggere come: "non avvertirmi di errori, directory complete".

1
Zorawar

Piccola variazione di 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

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

Sono sorpreso della guida wooledge sulle directory vuote non è stato menzionato. Questa guida, e tutta la lana veramente, è una lettura obbligata per le domande tipo Shell.

Da notare da quella pagina:

Non cercare mai di analizzare l'output di ls. Anche 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 posso inventare qualcosa che incredibilmente stupido).

In effetti, si potrebbe desiderare di evitare del tutto la domanda diretta. Di solito le persone vogliono sapere se un la directory è vuota perché vogliono fare qualcosa che coinvolga i file in essa contenuti, ecc. Guardare a domanda. 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 un test esplicito di directory vuote era necessario per evitare un messaggio di errore come mympgviewer: ./*.mpg: Nessun file o directory di questo tipo quando in realtà no tale test è richiesto.

0
bishop

Vorrei andare per 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 da 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
0
fedorqui

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"

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

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 vorrei controllare la presenza di eventuali file nella directory usando bourne Shell:

questo restituisce il numero di file in una directory:

ls -l <directory> | egrep -c "^-"

è possibile compilare il percorso della directory in cui è scritta la directory. La prima metà del tubo garantisce che il primo carattere di output sia "-" per ogni file. egrep quindi conta il numero di righe che iniziano con il 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 <directory> | egrep -c "^-"`  
 if [ $fileNum == x ] 
 then  
 #do what you want to do
 fi

x è una variabile di tua scelta.

0
Jecht Tyre

Prova con il comando find . Specifica la directory hardcoded o come argomento . Quindi avvia find per cercare tutti i file all'interno della directory . Controlla se il return di find è nullo . Echo i dati di find

#!/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
0
GiannakopoulosJ

Risposta semplice con bash :

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

Mescolando le cose e le ultime risposte di Prune, ci sono riuscito

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

che funziona anche per i percorsi con spazi

0
Laurent G