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

Bash scripting: test voor lege map

Ik wil testen of een directory geen bestanden bevat. Zo ja, dan sla ik wat verwerking over.

Ik heb het volgende geprobeerd:

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

Dat geeft de volgende foutmelding:

line 1: [: too many arguments

Is er een oplossing/alternatief?

Antwoorden (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

Ook zou het cool zijn om te controleren of de directory al bestaat.

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

Je hoeft niets te tellen of shell globs te gebruiken. Je kunt read ook gebruiken in combinatie met find. Als de uitvoer van find leeg is, krijg je false terug:

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

Dit zou portable moeten zijn.

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

Met FIND(1) (onder Linux en FreeBSD) kunt u niet-recursief naar een ingang in een map kijken via “-maxdepth 0” en testen of hij leeg is met “-empty”. Toegepast op de vraag geeft dit:

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

Een hacky, maar bash-only, PID-vrije manier:

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

Dit maakt gebruik van het feit dat de test builtin met 2 afsluit als er meer dan één argument na -e wordt gegeven: Eerst wordt "$1"/* glob geëxpandeerd door bash. Dit resulteert in één argument per bestand. Dus

  • Als er geen bestanden zijn, expandeert de asterisk in test -e "$1"* niet, dus valt Shell terug op het proberen van een bestand met de naam *, dat 1 teruggeeft.

  • …behalve als er wel een bestand is met de exacte naam *, dan breidt de asterisk zich uit tot asterisk, wat eindigt met dezelfde aanroep als hierboven, namelijk test -e "dir/*", maar deze keer levert het 0 op. (Bedankt @TrueY voor het opmerken van deze fout. )

  • Als er één bestand is, wordt test -e "dir/file" uitgevoerd, wat 0 teruggeeft.

  • Maar als er meer bestanden zijn dan 1, wordt test -e "dir/file1" "dir/file2" uitgevoerd, wat bash rapporteert als gebruiksfout, dus 2.

case omwikkelt de hele logica, zodat alleen het eerste geval, met 1 exit status wordt gerapporteerd als succes.

Mogelijke problemen die ik niet heb gecontroleerd:

  • Er zijn meer bestanden dan het aantal toegestane argumenten–Ik denk dat dit zich hetzelfde zou kunnen gedragen als bij 2+ bestanden.

  • Of er is een bestand met een lege naam–Ik weet niet zeker of dat mogelijk is op een gezond OS/FS.

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

Dit zal het werk doen in de huidige werkmap (.):

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

of hetzelfde commando gesplitst op drie regels om het leesbaarder te maken:

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

Vervang gewoon ls -1A . | wc -l door ls -1A <target-directory> | wc -l als je het op een andere doelmap moet uitvoeren.

Edit : Ik heb -1a vervangen door -1A (zie @Daniel commentaar)

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

Gebruik het volgende:

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

Op deze manier ben je onafhankelijk van het output formaat van ls. -mindepth slaat de directory zelf over, -maxdepth voorkomt recursief verdedigen in subdirectories om dingen te versnellen.

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

Gebruik een array:

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

Hoe zit het met het testen of de directory bestaat en niet leeg is in een if statement

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

Ik denk dat de beste oplossing is:

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

met dank aan https://stackoverflow.com/a/91558/520567

Dit is een anonieme bewerking van mijn antwoord dat al dan niet nuttig kan zijn voor iemand: Een kleine wijziging geeft het aantal bestanden:

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

Dit zal correct werken, zelfs als bestandsnamen spaties bevatten.

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

De vraag was:

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

Antwoord is:

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: Ik denk dat deze oplossing prima werkt met gnu find, na een snelle blik op de implementatie . Maar dit werkt misschien niet met, bijvoorbeeld, netbsd’s find . Inderdaad, die gebruikt stat(2)‘s st_size veld. De handleiding beschrijft het 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.

Een betere oplossing, ook eenvoudiger, is:

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

Ook de -prune in de 1e oplossing is nutteloos.

EDIT: geen -exit voor gnu find… de bovenstaande oplossing is goed voor NetBSD’s find. Voor GNU find, zou dit moeten werken:

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

Ik maakte deze aanpak:

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

Dit werkt voor mij, om bestanden in directory ../IN te controleren en te verwerken, aangezien het script in directory ../Script staat:

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

Dit is allemaal geweldig spul - ik heb er een script van gemaakt zodat ik kan controleren op lege mappen onder de huidige map. Het onderstaande moet in een bestand genaamd ‘findempty’ worden gezet, ergens in het pad worden geplaatst zodat bash het kan vinden en dan chmod 755 om uit te voeren. Kan gemakkelijk worden aangepast aan je specifieke behoeften denk ik.

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

Voor elke andere directory dan de huidige, kun je controleren of hij leeg is door te proberen hem te rmdiren, omdat rmdir gegarandeerd faalt voor niet-lege directories. Als rmdir slaagt, en je wilde eigenlijk dat de lege directory de test overleefde, dan mkdir je hem gewoon opnieuw.

Gebruik deze hack niet als er andere processen zijn die in de war kunnen raken doordat een directory waar ze van weten kort ophoudt te bestaan.

Als rmdir niet werkt voor jou, en je mogelijk mappen gaat testen die mogelijk grote aantallen bestanden kunnen bevatten, kan iedere oplossing die op shell globbing vertrouwt traag worden en/of tegen commandoregel lengte limieten aanlopen. In dat geval is het waarschijnlijk beter om find te gebruiken. De snelste find oplossing die ik kan bedenken gaat als

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

Dit werkt voor de GNU en BSD versies van find maar niet voor die van Solaris, die elk van die find operatoren mist. Ik hou van je werk, Oracle.

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

U kunt proberen de directory te verwijderen en wachten op een foutmelding; rmdir zal de directory niet verwijderen als deze niet leeg is.

_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