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

Skrypty Bash: test dla pustego katalogu

Chcę przetestować, czy katalog nie zawiera żadnych plików. Jeśli tak, to pominę niektóre przetwarzanie.

Próbowałem następująco:

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

To daje następujący błąd:

line 1: [: too many arguments

Czy istnieje jakieś rozwiązanie/alternatywa?

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

Fajnie byłoby też sprawdzić, czy katalog istnieje wcześniej.

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

Nie ma potrzeby liczenia czegokolwiek lub globów powłoki. Możesz również użyć read w połączeniu z find. Jeśli wyjście find jest puste, zwrócisz false:

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

To powinno być przenośne.

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

Za pomocą FIND(1) (pod Linuksem i FreeBSD) możesz nierekursywnie spojrzeć na wpis w katalogu poprzez “-maxdepth 0” i sprawdzić czy jest on pusty za pomocą “-empty”. Zastosowane do pytania daje to:

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

Sposób hacky, ale tylko w bashu, wolny od PID:

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

Wykorzystuje to fakt, że wbudowany test kończy pracę z 2, jeśli podano mu więcej niż jeden argument po -e: Najpierw, "$1"/* glob jest interpretowany przez bash. Powoduje to jeden argument na plik. Tak więc

  • Jeśli nie ma plików, gwiazdka w test -e "$1"* nie interpretuje się, więc Shell wraca do próbowania pliku o nazwie *, co zwraca 1.

  • …z wyjątkiem sytuacji, gdy faktycznie jest jeden plik o nazwie dokładnie *, wtedy gwiazdka rozszerza się do, cóż, gwiazdki, co kończy się tym samym wywołaniem co powyżej, tj. test -e "dir/*", tylko tym razem zwraca 0. (Dzięki @TrueY za zwrócenie na to uwagi. )

  • Jeśli jest jeden plik, uruchamiany jest test -e "dir/file", który zwraca 0.

  • Ale jeśli jest więcej plików niż 1, uruchamiany jest test -e "dir/file1" "dir/file2", który bash zgłasza to jako błąd użycia, czyli 2.

case opakowuje całą logikę tak, że tylko pierwszy przypadek, z 1 statusem wyjścia jest zgłaszany jako sukces.

Możliwe problemy, których nie sprawdziłem:

  • Jest więcej plików niż liczba dozwolonych argumentów - zgaduję, że może to zachowywać się podobnie do przypadku z 2+ plikami.

  • Albo faktycznie istnieje plik o pustej nazwie - nie jestem pewien czy jest to możliwe na jakimkolwiek zdrowym OS/FS.

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

To wykona zadanie w bieżącym katalogu roboczym (.):

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

lub to samo polecenie podzielone na trzy linie, aby było bardziej czytelne:

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

Wystarczy zastąpić ls -1A . | wc -l przez ls -1A <target-directory> | wc -l, jeśli musisz uruchomić go na innym folderze docelowym.

Edit : Zamieniłem -1a na -1A (zobacz komentarz @Daniel)

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

Użyj następującego:

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

W ten sposób jesteś niezależny od formatu wyjściowego ls. -mindepth pomija sam katalog, -maxdepth zapobiega rekurencyjnemu bronieniu się w podkatalogach, aby przyspieszyć działanie.

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

Użycie tablicy:

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

A co z testowaniem czy katalog istnieje i nie jest pusty w jednej instrukcji if

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

Myślę, że najlepszym rozwiązaniem jest:

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

dzięki https://stackoverflow.com/a/91558/520567

To jest anonimowa edycja mojej odpowiedzi, która może lub nie może być pomocna dla kogoś: Niewielka zmiana daje liczbę plików:

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

To będzie działać poprawnie, nawet jeśli nazwy plików zawierają spacje.

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

Pytanie brzmiało:

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

Odpowiedź brzmi:

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: Myślę, że to rozwiązanie działa dobrze z gnu find, po szybkim spojrzeniu na implementację . Ale to może nie działać, na przykład, z netbsd’s find . W rzeczywistości, ten używa pola st_size stat(2). Podręcznik opisuje je jako:

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.

Lepszym rozwiązaniem, również prostszym, jest:

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

Również -prune w 1. rozwiązaniu jest bezużyteczne.

EDIT: brak -exit dla gnu find… powyższe rozwiązanie jest dobre dla NetBSD find. Dla GNU find, to powinno zadziałać:

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

Zrobiłem takie podejście:

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

To działa dla mnie, aby sprawdzić i przetworzyć pliki w katalogu ../IN, biorąc pod uwagę, że skrypt jest w katalogu ../Script:

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

To wszystko są świetne rzeczy - właśnie zrobiłem z tego skrypt, dzięki któremu mogę sprawdzić, czy nie ma pustych katalogów poniżej bieżącego. Poniższy skrypt powinien być umieszczony w pliku o nazwie ‘findempty’, umieszczony gdzieś w ścieżce, tak aby bash mógł go znaleźć, a następnie chmod 755 aby go uruchomić. Może być łatwo zmieniony do twoich specyficznych potrzeb, jak sądzę.

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

Dla każdego katalogu innego niż bieżący, możesz sprawdzić, czy jest pusty, próbując go rmdir, ponieważ rmdir gwarantuje niepowodzenie dla niepustych katalogów. Jeśli rmdir się powiedzie, a chciałeś, aby pusty katalog przetrwał test, po prostu mkdir go ponownie.

Nie używaj tej sztuczki, jeśli istnieją inne procesy, które mogłyby się zdezorientować, gdyby katalog, o którym wiedzą, na krótko przestał istnieć.

Jeśli rmdir nie będzie dla ciebie działać, a możesz testować katalogi, które potencjalnie mogą zawierać dużą liczbę plików, każde rozwiązanie polegające na globalizacji powłoki może stać się powolne i/lub napotkać ograniczenia długości linii poleceń. Prawdopodobnie lepiej użyć find w tym przypadku. Najszybsze rozwiązanie find jakie przychodzi mi do głowy to

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

To działa dla wersji GNU i BSD find, ale nie dla Solarisa, któremu brakuje każdego z tych operatorów find. Kocham twoją pracę, Oracle.

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

Możesz spróbować usunąć katalog i poczekać na błąd; rmdir nie usunie katalogu, jeśli nie jest on pusty.

_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