2011-10-31 03:47:31 +0000 2011-10-31 03:47:31 +0000
106
106

Bash-Scripting: Test auf leeres Verzeichnis

Ich möchte testen, ob ein Verzeichnis keine Dateien enthält. Wenn ja, überspringe ich eine Verarbeitung.

Ich habe das Folgende versucht:

if [./* == "./*"]; then
    echo "No new file"
    exit 1
fi

Das ergibt den folgenden Fehler:

line 1: [: too many arguments

Gibt es eine Lösung/Alternative?

Antworten (18)

135
135
135
2011-10-31 03:53:28 +0000
if [-z "$(ls -A /path/to/dir)"]; then
   echo "Empty"
else
   echo "Not Empty"
fi

Außerdem wäre es cool, zu prüfen, ob das Verzeichnis schon existiert.

24
24
24
2013-10-29 21:07:29 +0000

Es ist nicht nötig, irgendetwas zu zählen oder Shell Globs zu verwenden. Sie können read auch in Kombination mit find verwenden. Wenn die Ausgabe von find leer ist, geben Sie false zurück:

if find /some/dir -mindepth 1 | read; then
   echo "dir not empty"
else
   echo "dir empty"
fi

Dies sollte portabel sein.

20
20
20
2011-10-31 10:53:57 +0000
if [-n "$(find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty 2>/dev/null)"]; then
    echo "Empty directory"
else
    echo "Not empty or NOT a directory"
fi
14
14
14
2011-11-01 14:51:09 +0000
#!/bin/bash
if [-d /path/to/dir]; then
    # the directory exists
    ["$(ls -A /path/to/dir)"] && echo "Not Empty" || echo "Empty"
else
    # You could check here if /path/to/dir is a file with [-f /path/to/dir]
fi
4
4
4
2018-09-26 13:50:40 +0000

Mit FIND(1) (unter Linux und FreeBSD) können Sie einen Verzeichniseintrag mit “-maxdepth 0” nicht-rekursiv betrachten und mit “-empty” testen, ob er leer ist. Auf die Frage angewandt ergibt dies:

if test -n "$(find ./ -maxdepth 0 -empty)" ; then
    echo "No new file"
    exit 1
fi
4
4
4
2014-10-24 01:23:28 +0000

Ein hacky, aber nur Bash, PID-freie Weg:

is_empty() {
    test -e "$1/"* 2>/dev/null
    case $? in
        1) return 0 ;;
        *) return 1 ;;
    esac
}

Dies nutzt die Tatsache, dass test builtin mit 2 beendet wird, wenn mehr als ein Argument nach -e gegeben wird: Zunächst wird "$1"/* glob von der Bash expandiert. Dadurch ergibt sich ein Argument pro Datei. Also

  • Wenn es keine Dateien gibt, wird der Stern in test -e "$1"* nicht expandiert, so dass die Shell auf den Versuch zurückfällt, eine Datei namens * zu versuchen, was 1 zurückgibt.

  • …außer wenn es tatsächlich eine Datei gibt, die genau * heißt, dann expandiert das Sternchen zu, nun ja, Sternchen, was auf den gleichen Aufruf wie oben hinausläuft, d.h. test -e "dir/*", nur diesmal mit dem Ergebnis 0. (Danke @TrueY für den Hinweis. )

  • Wenn es eine Datei gibt, wird test -e "dir/file" ausgeführt, was 0 zurückgibt.

  • Aber wenn es mehr als 1 Datei gibt, wird test -e "dir/file1" "dir/file2" ausgeführt, was die Bash als Nutzungsfehler meldet, d.h. 2.

case wickelt die ganze Logik um, so dass nur der erste Fall, mit 1 Exit-Status, als Erfolg gemeldet wird.

Mögliche Probleme, die ich nicht überprüft habe:

  • Es gibt mehr Dateien als die Anzahl der erlaubten Argumente - ich vermute, dies könnte sich ähnlich verhalten wie der Fall mit 2+ Dateien.

  • Oder es gibt tatsächlich eine Datei mit einem leeren Namen - ich bin mir nicht sicher, ob das auf einem vernünftigen Betriebssystem/FS möglich ist.

4
4
4
2011-10-31 10:06:28 +0000

Dies erledigt die Aufgabe im aktuellen Arbeitsverzeichnis (.):

[`ls -1A . | wc -l` -eq 0] && echo "Current dir is empty." || echo "Current dir has files (or hidden files) in it."

oder derselbe Befehl auf drei Zeilen aufgeteilt, nur um besser lesbar zu sein:

[`ls -1A . | wc -l` -eq 0] && \
echo "Current dir is empty." || \
echo "Current dir has files (or hidden files) in it."

Ersetzen Sie einfach ls -1A . | wc -l durch ls -1A <target-directory> | wc -l, wenn Sie es in einem anderen Zielverzeichnis ausführen müssen.

Edit : Ich habe -1a durch -1A ersetzt (siehe Kommentar von @Daniel)

3
3
3
2011-10-31 10:17:15 +0000

Verwenden Sie Folgendes:

count="$( find /path -mindepth 1 -maxdepth 1 | wc -l )"
if [$count -eq 0] ; then
   echo "No new file"
   exit 1
fi

Auf diese Weise sind Sie unabhängig von dem Ausgabeformat von ls. -mindepth überspringt das Verzeichnis selbst, -maxdepth verhindert das rekursive Verteidigen in Unterverzeichnisse, um die Dinge zu beschleunigen.

3
3
3
2014-08-12 21:46:08 +0000

Verwendung eines Arrays:

files=( * .* )
if (( ${#files[@]} == 2 )); then
    # contents of files array is (. ..)
    echo dir is empty
fi
2
2
2
2018-06-20 09:17:01 +0000

Wie wäre es zu testen, ob das Verzeichnis existiert und nicht leer ist in einer if-Anweisung

if [[-d path/to/dir && -n "$(ls -A path/to/dir)"]]; then 
  echo "directory exists"
else
  echo "directory doesn't exist"
fi
1
1
1
2013-10-29 20:57:27 +0000

Ich denke, die beste Lösung ist:

files=$(shopt -s nullglob; shopt -s dotglob; echo /MYPATH/*)
[["$files"]] || echo "dir empty"

Dank an https://stackoverflow.com/a/91558/520567

Dies ist eine anonyme Bearbeitung meiner Antwort, die für jemanden hilfreich sein könnte oder auch nicht: Eine kleine Änderung ergibt die Anzahl der Dateien:

files=$(shopt -s nullglob dotglob; s=(MYPATH/*); echo ${s[*]}) 
echo "MYPATH contains $files files"

Dies funktioniert auch dann korrekt, wenn die Dateinamen Leerzeichen enthalten.

1
1
1
2020-02-16 18:53:46 +0000

Die Frage war:

if [./* == "./*"]; then
    echo "No new file"
    exit 1
fi

Antwort ist:

if ls -1qA . | grep -q .
    then ! exit 1
    else : # Dir is empty
fi
1
1
1
2018-05-25 17:06:53 +0000
if find "${DIR}" -prune ! -empty -exit 1; then
    echo Empty
else
    echo Not Empty
fi

EDIT: Ich denke, dass diese Lösung mit gnu find gut funktioniert, nach einem schnellen Blick auf die Implementierung . Aber das funktioniert vielleicht nicht mit, zum Beispiel, netbsd’s find . Dieser verwendet nämlich das Feld st_size von stat(2). Das Handbuch beschreibt es als:

st_size The size of the file in bytes. The meaning of the size
                   reported for a directory is file system dependent.
                   Some file systems (e.g. FFS) return the total size used
                   for the directory metadata, possibly including free
                   slots; others (notably ZFS) return the number of
                   entries in the directory. Some may also return other
                   things or always report zero.

Eine bessere Lösung, die auch einfacher ist, ist:

if find "${DIR}" -mindepth 1 -exit 1; then
    echo Empty
else
    echo Not Empty
fi

Außerdem ist das -prune in der 1.

EDIT: kein -exit für gnu find… die obige Lösung ist gut für NetBSD’s find. Für GNU find sollte dies funktionieren:

if [-z "`find \"${DIR}\" -mindepth 1 -exec echo notempty \; -quit`"]; then
    echo Empty
else
    echo Not Empty
fi
0
0
0
2020-01-15 17:46:01 +0000

Ich habe diesen Ansatz gemacht:

CHECKEMPTYFOLDER=$(test -z "$(ls -A /path/to/dir)"; echo $?)
if [$CHECKEMPTYFOLDER -eq 0]
then
  echo "Empty"
elif [$CHECKEMPTYFOLDER -eq 1]
then
  echo "Not Empty"
else
  echo "Error"
fi
0
0
0
2018-05-02 13:29:51 +0000

Dies funktioniert bei mir, um Dateien im Verzeichnis ../IN zu prüfen und zu verarbeiten, da sich das Skript im Verzeichnis ../Script befindet:

FileTotalCount=0

    for file in ../IN/*; do
    FileTotalCount=`expr $FileTotalCount + 1`
done

if test "$file" = "../IN/*"
then

    echo "EXITING: NO files available for processing in ../IN directory. "
    exit

else

  echo "Starting Process: Found ""$FileTotalCount"" files in ../IN directory for processing."

# Rest of the Code
0
0
0
2012-02-24 10:06:37 +0000

Das ist alles tolles Zeug - habe gerade ein Skript daraus gemacht, damit ich nach leeren Verzeichnissen unterhalb des aktuellen suchen kann. Das Folgende sollte in eine Datei namens ‘findempty’ geschrieben werden, irgendwo im Pfad platziert werden, damit die Bash es finden kann, und dann mit chmod 755 ausgeführt werden. Kann leicht an Ihre speziellen Bedürfnisse angepasst werden, denke ich.

#!/bin/bash
if ["$#" == "0"]; then 
find . -maxdepth 1 -type d -exec findempty "{}" \;
exit
fi

COUNT=`ls -1A "$*" | wc -l`
if ["$COUNT" == "0"]; then 
echo "$* : $COUNT"
fi
-1
-1
-1
2018-01-10 17:12:56 +0000

Für jedes beliebige Verzeichnis außer dem aktuellen können Sie prüfen, ob es leer ist, indem Sie versuchen, es mit rmdir zu belegen, denn rmdir schlägt bei nicht leeren Verzeichnissen garantiert fehl. Wenn rmdir erfolgreich ist und Sie eigentlich wollten, dass das leere Verzeichnis den Test überlebt, führen Sie einfach erneut mkdir aus.

Verwenden Sie diesen Hack nicht, wenn es andere Prozesse gibt, die durch ein Verzeichnis, von dem sie wissen, dass es kurzzeitig nicht mehr existiert, verwirrt werden könnten.

Wenn rmdir für Sie nicht funktioniert und Sie Verzeichnisse testen, die möglicherweise eine große Anzahl von Dateien enthalten, könnte jede Lösung, die auf Shell-Globbing beruht, langsam werden und/oder an die Grenzen der Befehlszeilenlänge stoßen. Wahrscheinlich ist es in diesem Fall besser, find zu verwenden. Die schnellste find-Lösung, die mir einfällt, geht so:

is_empty() {
    test -z $(find "$1" -mindepth 1 -printf X -quit)
}

Das funktioniert für die GNU- und BSD-Versionen von find, aber nicht für die Solaris-Version, der jeder einzelne dieser find-Operatoren fehlt. Ich liebe deine Arbeit, Oracle.

-3
-3
-3
2018-04-08 20:54:13 +0000

Sie können versuchen, das Verzeichnis zu entfernen und auf einen Fehler warten; rmdir wird das Verzeichnis nicht löschen, wenn es nicht leer ist.

_path="some/path"
if rmdir $_path >/dev/null 2>&1; then
   mkdir $_path # create it again
   echo "Empty"
else
   echo "Not empty or doesn't exist"
fi