Überprüfen anhand des Shell-Skripts, ob ein Verzeichnis Dateien enthält


116

Wie überprüfe ich anhand eines Shell-Skripts, ob ein Verzeichnis Dateien enthält?

Ähnliches

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

Dies funktioniert jedoch, wenn das Verzeichnis eine oder mehrere Dateien enthält (die obige Datei funktioniert nur mit genau 0 oder 1 Dateien).


Für das, was Ihr Beispiel wert ist, tut gut, was Sie in ksh und zsh wollen
Dave Webb

2
@ DaveWebb Nein, tut es nicht. Wenn der Glob auf mehr als ein Wort erweitert wird, meldet der zsh-Test "Test: zu viele Argumente".
Jens

"huzzah" bedeutet "das Verzeichnis ist nicht leer".
Funroll

Wenn das Verzeichnis nur ein leeres Unterverzeichnis enthält, zählt dies als "Dateien enthalten"?
Keith Thompson

Antworten:


71

Die bisherigen Lösungen nutzen ls. Hier ist eine All-Bash-Lösung:

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

8
solange Sie daran denken, die Optionen am Ende des Skripts auf ihren ursprünglichen Wert zurückzusetzen :)
Jean

Dies ist eine leicht verbesserte Version, die sich um das Zurücksetzen der Bash-Einstellungen shopt -q nullglob || resetnullglob=1; shopt -s nullglob; shopt -q dotglob || resetdotglob=1; shopt -s dotglob; files=(/some/dir/*); [ "$files" ] && echo "wowzers"; [ "$resetdotglob" ] && shopt -u dotglob; [ "$resetnullglob" ] && shopt -u nullglob;
kümmert

12
Warum nicht eine Subshell verwenden, um die Einstellungen zurückzusetzen:files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*)
Teambob

7
@teambob bei Verwendung einer Sub-Shell: files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*) Dann sollte sich die if-Anweisung in ändern if [ ${#files} -gt 0 ];oder haben Sie einfach das () um den Sub-Shell-Befehl vergessen? files=($(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*))
Stoutyhk

2
@stoutyhk $ (...) stellt die Einstellungen wieder her, es ist keine separate Subshell erforderlich. Die Verwendung von $ (...) erzeugt eine neue Instanz der Shell. Die Umgebung dieser neuen Instanz wird weggeworfen, sobald der Befehl beendet ist. Bearbeiten: Referenz gefunden tldp.org/LDP/abs/html/commandsub.html "Befehlssubstitution ruft eine Subshell auf."
Teambob

139

Drei beste Tricks


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

Dieser Trick ist 100% bashund ruft eine Sub-Shell auf (erzeugt sie). Die Idee stammt von Bruno De Fraine und wurde durch den Kommentar von Teambob verbessert .

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

Hinweis: Kein Unterschied zwischen einem leeren und einem nicht vorhandenen Verzeichnis (und selbst wenn der angegebene Pfad eine Datei ist).

Es gibt eine ähnliche Alternative und weitere Details (und weitere Beispiele) in den 'offiziellen' FAQ für den # bash IRC-Kanal :

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)" ]

Dieser Trick ist von dem 2007 veröffentlichten Artikel von nixCraft inspiriert . Hinzufügen 2>/dev/null, um den Ausgabefehler zu unterdrücken "No such file or directory".
Siehe auch Andrew Taylors Antwort (2008) und gr8can8dians Antwort (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

oder die einzeilige Bashism-Version:

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

Hinweis: ls Gibt zurück, $?=2wenn das Verzeichnis nicht vorhanden ist. Aber kein Unterschied zwischen einer Datei und einem leeren Verzeichnis.


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

Dieser letzte Trick ist inspiriert von der Antwort von gravstar, bei der -maxdepth 0er durch den Kommentar -prunevon phils ersetzt und verbessert wird .

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

eine Variation mit -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

Erläuterung:

  • find -pruneist ähnlich wie find -maxdepth 0mit weniger Zeichen
  • find -empty druckt die leeren Verzeichnisse und Dateien
  • find -type d druckt nur Verzeichnisse

Hinweis: Sie können auch [ -n "$(find your/dir -prune -empty)" ]nur die folgende Kurzversion ersetzen :

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

Dieser letzte Code funktioniert in den meisten Fällen, aber beachten Sie, dass böswillige Pfade einen Befehl ausdrücken können ...


2
Ich denke, Sie können die Suchoption vereinfachen [ -n "$(find "your/dir" -prune -empty)" ], um die Wiederholung des Verzeichnispfads zu vermeiden.
Phils

Bei der Verwendung if [ ``ls -A your/dir`` ]in einem Skript bin ich zu dem Schluss gekommen, dass es für ein Verzeichnis mit 0, 1 oder 2 Unterverzeichnissen gut funktioniert, für ein Verzeichnis mit mehr als 2 Unterverzeichnissen jedoch fehlschlägt. line 17: [: 20150424-002813: unary operator expectedWo 20150424-002813war einer der Verzeichnisnamen? Die benutzte Schale war /bin/bash/. Ich habe es schließlich geändert inls "$destination" | tail -1
Christophe De Troyer

Hallo @ChristopheDeTroyer Ich kann Ihr Problem nicht reproduzieren. Auf meiner Seite if [ ``ls -A my/dir`` ]geht bei Irrtum aus bash: [: -A: binary operator expected. Getestet mit den Bash-Versionen 4.1.2 und 4.2.53.
Olibre

1
Nun, ich war hauptsächlich wegen der wahrgenommenen Inkonsistenz zu Kommentaren motiviert (da die -nVariante in der Überschrift stand, dann aber nicht im folgenden Absatz). Also ja, es ist in Ordnung.
Maxschlepzig

1
Ich verwende Ihre -n-Lösung, aber mein Skript beschwert sich immer noch darüber ls: cannot access '/path': No such file or directory. Gibt es eine Möglichkeit, diese Nachricht zu unterdrücken? Ich würde dort gerne still scheitern.
Freedo

48

Wie wäre es mit folgendem:

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

Auf diese Weise muss keine vollständige Liste des Inhalts des Verzeichnisses erstellt werden. Die readbeiden ist die Ausgabe zu verwerfen und machen den Ausdruck auswerten nur wahr , wenn etwas gelesen wird (dh /some/dir/leer durch gefunden find).


3
oder einfachfind /some/dir/ -maxdepth 0 -empty -exec echo "huzzah" \;
doubleDown

5
+1 Dies ist die eleganteste Lösung. Es beinhaltet keine Analyse der lsAusgabe und ist nicht auf nicht standardmäßige Shell-Funktionen angewiesen.

7
Es stützt sich jedoch auf die Nicht-Standard- -maxdepthund -emptyPrimärfarben.
Chepner

21

Versuchen:

if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi

Das hat bei mir funktioniert, aber ich kann diese d * mn-Nachricht nicht formatieren !!! <br> export tmp = /bin/ls <some_dir>/* 2> /dev/nullif [! -z "$ tmp"]; dann echo Etwas ist da fi
AndrewStone

1
Wenn Sie für Bash-Idioten wie mich das Gegenteil überprüfen möchten - dass das Verzeichnis leer ist - verwenden Sie einfach if [-z ls /some/dir/*]; dann echo "huzzah"; fi
Chris Moschini

4
Sie können -nanstelle von verwenden ! -z(beide sind gleichwertig, aber warum nicht die kürzere Form verwenden, wenn sie vorhanden ist) ?
n.st

Wenn ZSH in diesem Beispiel einen Fehler auslöst, besteht die Idee darin, den Fehler nicht auszulösen ... BigGray% if [ ! -z ls / some / dir / * `]; dann echo "huzzah"; fi zsh: keine Übereinstimmungen gefunden: / some / dir / * `
Hvisage

funktioniert nicht für mich ohne doppelte Anführungszeichen ls...in Bash
Letmutx

15
# 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
}

15

Achten Sie auf Verzeichnisse mit vielen Dateien! Die Auswertung des lsBefehls kann einige Zeit dauern .

IMO ist die beste Lösung die, die verwendet

find /some/dir/ -maxdepth 0 -empty

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

6

Könnten Sie die Ausgabe davon vergleichen?

 ls -A /some/dir | wc -l

4
# Überprüft, ob ein Verzeichnis nicht ausgeblendete Dateien enthält.
#
# use: if isempty "$ HOME"; dann Echo "Willkommen zu Hause"; fi
#
ist leer() {
    für _ief in $ 1 / *; machen
        if [-e "$ _ief"]; dann
            Rückgabe 1
        fi
    getan
    0 zurückgeben
}}

Einige Implementierungshinweise:

  • Die forSchleife vermeidet einen Aufruf eines externen lsProzesses. Es werden immer noch alle Verzeichniseinträge einmal gelesen. Dies kann nur durch Schreiben eines C-Programms optimiert werden, das readdir () explizit verwendet.
  • Das test -eInnere der Schleife fängt den Fall eines leeren Verzeichnisses ab. In diesem Fall würde der Variablen _iefder Wert "somedir / *" zugewiesen. Nur wenn diese Datei vorhanden ist, gibt die Funktion "nicht leer" zurück.
  • Diese Funktion funktioniert in allen POSIX-Implementierungen. Beachten Sie jedoch, dass Solaris / bin / sh nicht in diese Kategorie fällt. Seine testImplementierung unterstützt das -eFlag nicht.

1
Dies würde Punktdateien im Verzeichnis ignorieren, wenn dotglobnicht gesetzt ist -shopt -s dotglob
l0b0

4

Dies sagt mir, ob das Verzeichnis leer ist oder nicht, wie viele Dateien es enthält.

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

Kann mir jemand erklären, warum ich abgelehnt wurde? Wenn ich Craps schreibe, würde ich gerne wissen warum;)
Daishi

1
Ich habe das nicht abgelehnt, aber vermutlich liegt es daran, dass Sie die Ausgabe von analysierenls .
Toby Speight

Ist der verlinkte Artikel unklar? Wenn ja, senden Sie eine E-Mail an den Autor (nicht an mich).
Toby Speight

1
@TobySpeight Ich verstehe den Punkt. Aber in diesem Fall zähle ich die Zeilen, die sie nicht aufzählen. Es sollte nur dann ein falsches Ergebnis liefern, wenn ein Dateiname eine neue Zeile enthält. Und wenn Dateinamen neue Zeilen enthalten, muss irgendwo etwas viel Wichtigeres aufgetaucht sein;)
Daishi

3

Dies mag eine sehr späte Antwort sein, aber hier ist eine Lösung, die funktioniert. Diese Zeile erkennt nur das Vorhandensein von Dateien! Es gibt kein falsches Positiv, wenn Verzeichnisse vorhanden sind.

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

2
dir_is_empty() {
   [ "${1##*/}" = "*" ]
}

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

Angenommen , Sie nicht über eine Datei mit dem Namen haben *in /any/dir/you/check, sollte es funktionieren auf bash dash posh busybox shund zshaber (für zsh) erfordern unsetopt nomatch.

Die Leistung sollte mit jeder lsVerwendung vergleichbar sein *(glob). Ich denke, sie wird in Verzeichnissen mit vielen Knoten langsam sein (meine /usr/binmit mehr als 3000 Dateien waren nicht so langsam). Sie wird mindestens genug Speicher verwenden, um alle Verzeichnisse / Dateinamen (und mehr) zuzuweisen. Da sie alle als Argumente an die Funktion übergeben (aufgelöst) werden, haben einige Shell wahrscheinlich Grenzen für die Anzahl der Argumente und / oder die Länge der Argumente.

Eine tragbare schnelle O (1) Null-Ressourcen-Methode, um zu überprüfen, ob ein Verzeichnis leer ist, wäre schön.

aktualisieren

Die obige Version berücksichtigt keine versteckten Dateien / Verzeichnisse, falls weitere Tests erforderlich sind, wie die Tricksis_empty von Rich's 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 )

Aber stattdessen denke ich über so etwas nach:

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

Einige Bedenken hinsichtlich nachlaufender Schrägstriche, die sich vom Argument und der Suchausgabe unterscheiden, wenn das Verzeichnis leer ist, und nachgestellten Zeilenumbrüchen (dies sollte jedoch einfach zu handhaben sein), leider in meiner busybox shShow, was wahrscheinlich ein Fehler in der find -> ddPipe ist, bei dem die Ausgabe zufällig abgeschnitten wurde ( Wenn ich verwendet habe, ist catdie Ausgabe immer die gleiche, scheint ddmit dem Argument zu sein count).


Ich liebe die tragbare Lösung. Ich bin gekommen, um die gleiche Antwort zu geben. Ich hatte es gerade anders geschrieben (Rückgabe 2, wenn kein Verzeichnis). Diese tragbaren Lösungen haben außerdem den Vorteil, dass keine externen Programme aufgerufen werden, was für eingeschränkte oder eingebettete Systeme von Vorteil sein kann. Ich mache mir nur Sorgen, dass die Verwendung von "()" einen neuen Unterprozess erzeugen könnte (oder zumindest zwingt, Umgebung und Material zu kopieren und dann zurückzuschalten). Schauen Sie sich das an: is_empty () {_d = "$ {1: -.}"; [! -d "$ {_ d}"] && return 2; set - "$ {_ d}" / * "$ {_ d}" /.[!.‹* "$ {_ d}" /..?*; ["$ { }" = "$ {_ d} / $ {_ d} /. [!] * $ {_ d} /..?*"]; };
Diego Augusto Molina

@DiegoAugustoMolina Kürzlich in einem Projekt musste ich diesen Test erneut durchführen. Wenn ein Verzeichnis leer war, habe ich zu Beginn Python verwendet. Da ich Python praktisch nur dafür installiert habe, habe ich den Test in c implementiert. Die Implementierung ist extrem Banalität, ich frage mich, warum es nie als Test oder als eigenständiger Befehl hinzugefügt wurde
Alex

1
Auch ich brauchte kürzlich eine Lösung für dieses Problem für ein (wirklich) eingeschränktes System. Ich habe sogar den vorherigen Code ein wenig optimiert, um überhaupt keine zusätzlichen Variablen zu verwenden. Hackisch und hässlich aussehender Einzeiler, aber großartig. Bedienen Sie sich:is_empty(){ [ ! -d "${1}" ] && return 2;set -- "${1}" "${1}"/* "${1}"/.[!.]* "${1}"/..?*;[ "${*}" = "${1} ${1}/* ${1}/.[!.]* ${1}/..?*" ]; };
Diego Augusto Molina

2

ZSH

Ich weiß, dass die Frage für Bash markiert wurde; aber nur als Referenz für zsh- Benutzer:

Test auf nicht leeres Verzeichnis

So überprüfen Sie, ob fooes nicht leer ist:

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

Wenn foonicht leer, wird der Code im forBlock ausgeführt.

Test auf leeres Verzeichnis

So überprüfen Sie, ob fooes leer ist:

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

Wenn fooleer, wird der Code im forBlock ausgeführt.

Anmerkungen

Wir mussten das fooobige Verzeichnis nicht zitieren , aber wir können dies tun, wenn wir:

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

Wir können auch mehr als ein Objekt testen, auch wenn es kein Verzeichnis ist:

$ 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

Alles, was kein Verzeichnis ist, wird einfach ignoriert.

Extras

Da wir globben, können wir jeden Glob (oder jede Klammererweiterung) verwenden:

$ 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

Wir können auch Objekte untersuchen, die in einem Array platziert sind. Mit den Verzeichnissen wie oben zum Beispiel:

$ 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

Auf diese Weise können wir Objekte testen, die möglicherweise bereits in einem Array-Parameter festgelegt sind.

Beachten Sie, dass der Code im forBlock offensichtlich nacheinander in jedem Verzeichnis ausgeführt wird. Wenn dies nicht wünschenswert ist, können Sie einfach einen Array-Parameter auffüllen und dann diesen Parameter bearbeiten:

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

Erläuterung

Für zsh-Benutzer gibt es das (F)Glob-Qualifikationsmerkmal (siehe man zshexpn), das mit "vollständigen" (nicht leeren) Verzeichnissen übereinstimmt:

$ 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/

Das Qualifikationsmerkmal (F)listet übereinstimmende Objekte auf: ist ein Verzeichnis UND ist nicht leer. Also, (^F)stimmt überein: kein Verzeichnis ODER ist leer. So (^F)würde allein beispielsweise auch reguläre Dateien aufgelistet. Wie auf der zshexpManpage erläutert , benötigen wir daher auch das (/)Glob-Qualifikationsmerkmal, das nur Verzeichnisse auflistet:

$ 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

Um zu überprüfen, ob ein bestimmtes Verzeichnis leer ist, können Sie Folgendes ausführen:

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

und nur um sicherzugehen, dass ein nicht leeres Verzeichnis nicht erfasst wird:

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

Hoppla! Da Yzsh nicht leer ist, findet zsh keine Übereinstimmungen für (/^F)("Verzeichnisse, die leer sind") und gibt daher eine Fehlermeldung aus, dass keine Übereinstimmungen für den Glob gefunden wurden. Wir müssen daher diese möglichen Fehlermeldungen mit dem (N)Glob-Qualifikationsmerkmal unterdrücken :

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

Für leere Verzeichnisse benötigen wir daher das Qualifikationsmerkmal (N/^F), das Sie wie folgt lesen können: "Warnen Sie mich nicht vor Fehlern, Verzeichnissen, die nicht voll sind".

Ebenso benötigen wir für nicht leere Verzeichnisse das Qualifikationsmerkmal (NF), das wir ebenfalls lesen können: "Warnen Sie mich nicht vor Fehlern, vollständige Verzeichnisse".


1

Ich bin überrascht, dass der Wooledge-Leitfaden für leere Verzeichnisse nicht erwähnt wurde. Dieser Leitfaden und wirklich alles von Wooledge ist ein Muss für Fragen zum Muscheltyp.

Bemerkenswert von dieser Seite:

Versuchen Sie niemals, die Ausgabe zu analysieren. Sogar ls-A-Lösungen können kaputt gehen (z. B. unter HP-UX, wenn Sie root sind, macht ls -A genau das Gegenteil von dem, was es macht, wenn Sie nicht root sind - und nein, ich kann etwas nicht so unglaublich erfinden blöd).

In der Tat möchte man vielleicht die direkte Frage ganz vermeiden. Normalerweise möchten die Leute wissen, ob ein Verzeichnis leer ist, weil sie etwas tun möchten, das die darin enthaltenen Dateien usw. betrifft. Schauen Sie sich die größere Frage an. Beispielsweise kann eines dieser fundbasierten Beispiele eine geeignete Lösung sein:

   # 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

Am häufigsten wird nur Folgendes benötigt:

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

Mit anderen Worten, die Person, die die Frage stellt, hat möglicherweise gedacht, dass ein expliziter Test für leere Verzeichnisse erforderlich ist, um eine Fehlermeldung wie mympgviewer zu vermeiden: ./*.mpg: Keine solche Datei oder kein solches Verzeichnis, obwohl tatsächlich kein solcher Test erforderlich ist.


1

Kleine Variation von Brunos Antwort :

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

Für mich geht das


1

Ich nehme einen Hinweis (oder mehrere) aus der Antwort von olibre und mag eine Bash-Funktion:

function isEmptyDir {
  [ -d $1 -a -n "$( find $1 -prune -empty 2>/dev/null )" ]
}

Denn während es eine Unterschale erstellt, kommt es einer O (1) -Lösung so nahe, wie ich es mir vorstellen kann, und wenn man ihr einen Namen gibt, ist sie lesbar. Ich kann dann schreiben

if isEmptyDir somedir
then
  echo somedir is an empty directory
else
  echo somedir does not exist, is not a dir, is unreadable, or is  not empty
fi

Was O (1) betrifft, gibt es Ausreißerfälle: Wenn in einem großen Verzeichnis alle oder alle bis auf den letzten Eintrag gelöscht wurden, muss "find" möglicherweise das Ganze lesen, um festzustellen, ob es leer ist. Ich glaube, dass die erwartete Leistung O (1) ist, aber im schlimmsten Fall ist die Verzeichnisgröße linear. Ich habe das nicht gemessen.


0

Bisher habe ich keine Antwort gesehen, die grep verwendet, was meiner Meinung nach eine einfachere Antwort geben würde (mit nicht zu vielen seltsamen Symbolen!). So würde ich mithilfe der Bourne-Shell überprüfen, ob Dateien im Verzeichnis vorhanden sind:

Dies gibt die Anzahl der Dateien in einem Verzeichnis zurück:

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

Sie können den Verzeichnispfad eingeben, in den das Verzeichnis geschrieben wurde. Die erste Hälfte der Pipe stellt sicher, dass das erste Zeichen der Ausgabe für jede Datei "-" ist. egrep zählt dann die Anzahl der Zeilen, die mit diesem Symbol beginnen, unter Verwendung regulärer Ausdrücke. Jetzt müssen Sie nur noch die Nummer speichern, die Sie erhalten, und sie mit Anführungszeichen wie den folgenden vergleichen:

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

x ist eine Variable Ihrer Wahl.


0

Ich mischte Pflaumensachen und letzte Antworten und musste

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

Das funktioniert auch für Pfade mit Leerzeichen



0

Ich würde gehen für find:

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

Dies überprüft die Ausgabe der Suche nach nur Dateien im Verzeichnis, ohne die Unterverzeichnisse zu durchlaufen. Anschließend wird die Ausgabe mit der folgenden -zOption überprüft man test:

   -z STRING
          the length of STRING is zero

Sehen Sie einige Ergebnisse:

$ mkdir aaa
$ dir="aaa"

Leeres Verzeichnis:

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

Nur dirs drin:

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

Eine Datei im Verzeichnis:

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

Eine Datei in einem Unterverzeichnis:

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

0

Mit einer Problemumgehung konnte ich auf einfache Weise herausfinden, ob sich Dateien in einem Verzeichnis befinden. Dies kann mit grep-Befehlen erweitert werden, um speziell XML- oder TXT-Dateien usw. zu überprüfen. Beispiel: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

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

Ich mag dieses, da es keine Anführungszeichen oder Klammern gibt, die den Befehl zusammenfassen.
Dave Webb

Achten Sie darauf nullglob, dies nicht zu verwenden, wenn Sie festlegen , da der lsBefehl dann erfolgreich ist.
Steve Kehlet

Funktioniert nicht in allen Umgebungen, wenn das Verzeichnis Punktedateien enthält.
Diego Augusto Molina

-1

um ein bestimmtes Zielverzeichnis zu testen

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;

-1

Versuchen Sie es mit dem Befehl find. Geben Sie das Verzeichnis fest oder als Argument an. Starten Sie dann find, um alle Dateien im Verzeichnis zu durchsuchen. Überprüfen Sie, ob die Rückgabe des Funds null ist. Echo die Daten von 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

Wenn das Verzeichnis leere Verzeichnisse oder nicht reguläre Dateien (Sockets, Zeichengeräte, Symlinks usw.) enthält, funktioniert dies nicht. Das Verzeichnis wird als leer gemeldet.
Diego Augusto Molina

@DiegoAugustoMolina Wenn ich in der Frage richtig verstanden habe, dass wir prüfen wollen, ob Dateien vorhanden sind (als Dateien im Literal), wurde das Argument -f verwendet. aber Ihre Kommentare bleiben immer noch wahr.
Igiannak

-2

Ich mag die veröffentlichten ls - ALösungen nicht. Höchstwahrscheinlich möchten Sie testen, ob das Verzeichnis leer ist, weil Sie es nicht löschen möchten. Das Folgende macht das. Wenn Sie jedoch nur eine leere Datei protokollieren möchten, ist das Löschen und Neuerstellen dieser Datei sicherlich schneller als das Auflisten möglicherweise unendlicher Dateien?

Das sollte funktionieren...

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

4
Dies funktioniert nicht, wenn der Benutzer keine Schreibberechtigung dafür hat ${target}/...
Jens

Nur eine schlechte Idee, einen Test destruktiv zu machen. Unter anderem werden die Rennbedingungen eingeführt.
4dummies

-2

Funktioniert gut für mich dies (wenn dir existiert):

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

Mit voller Kontrolle:

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.