81

Я хочу проверить, не содержит ли каталог никаких файлов. Если так, я пропущу некоторую обработку.

Я попробовал следующее:

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

Это дает следующую ошибку:

line 1: [: too many arguments

Есть ли решение / альтернатива?

16 ответов16

102
if [ -z "$(ls -A /path/to/dir)" ]; then
   echo "Empty"
else
   echo "Not Empty"
fi

Также было бы здорово проверить, существует ли каталог раньше.

17
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
16

Нет необходимости считать что-либо или ракушки. Вы также можете использовать read в сочетании с find . Если вывод find пуст, вы вернете false:

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

Это должно быть портативным.

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

Это сделает работу в текущем рабочем каталоге (.):

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

или та же команда разделена на три строки, чтобы быть более читабельной:

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

Просто замените ls -1A . | wc -l с ls -1A <target-directory> | wc -l если вам нужно запустить его в другой целевой папке.

Редактировать: я заменил -1a -1A (см. Комментарий @Daniel)

3

Используйте следующее:

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

Таким образом, вы не зависите от формата вывода ls . -mindepth пропускает сам каталог, -maxdepth предотвращает рекурсивную защиту в подкаталогах для ускорения работы.

3

Хакерский, но бездарный, без PID способ:

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

Это использует тот факт, что встроенная команда test завершается с 2, если задано более одного аргумента после -e: во-первых, глобус "$1"/* расширяется с помощью bash. Это приводит к одному аргументу на файл. Так

  • Если файлов нет, звездочка в test -e "$1"* не раскрывается, поэтому Shell возвращается к файлу с именем * , который возвращает 1.

  • ... за исключением случаев, когда на самом деле есть один файл с именем точно * , тогда звездочка расширяется до нуля, звездочка, которая заканчивается тем же вызовом, что и выше, т.е. test -e "dir/*" , только на этот раз возвращает 0. (Спасибо @TrueY за указание на это.)

  • Если есть один файл, запускается test -e "dir/file" , который возвращает 0.

  • Но если файлов больше, чем 1, запускается test -e "dir/file1" "dir/file2" , который bash сообщает об этом как об ошибке использования, то есть 2.

case оборачивает всю логику так, что только первый случай с 1 состоянием выхода сообщается как успешный.

Возможные проблемы, которые я не проверял:

  • Есть больше файлов, чем количество разрешенных аргументов - я думаю, это может вести себя подобно случаю с 2+ файлами.

  • Или на самом деле есть файл с пустым именем - я не уверен, что это возможно на любой вменяемой OS/FS.

3

Используя массив:

files=( * .* )
if (( ${#files[@]} == 2 )); then
    # contents of files array is (. ..)
    echo dir is empty
fi
2

С FIND(1) (под Linux и FreeBSD) вы можете нерекурсивно просматривать запись каталога с помощью "-maxdepth 0" и проверять, является ли она пустой с помощью "-empty". Применительно к вопросу это дает:

if test -n "$(find ./ -maxdepth 0 -empty)" ; then
    echo "No new file"
    exit 1
fi
1
if find "${DIR}" -prune ! -empty -exit 1; then
    echo Empty
else
    echo Not Empty
fi

РЕДАКТИРОВАТЬ: Я думаю, что это решение отлично работает с GNU Find, после быстрого взгляда на реализацию. Но это может не работать, например, с поиском netbsd. Действительно, он использует поле st_size stat(2). Руководство описывает это как:

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.

Лучшее решение, также более простое:

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

Кроме того, -прень в 1-м решении бесполезна.

РЕДАКТИРОВАТЬ: нет-выход для gnu find .. вышеприведенное решение хорошо для поиска в NetBSD. Для GNU find это должно работать:

if [ -z "`find \"${DIR}\" -mindepth 1 -exec echo notempty \; -quit`" ]; then
    echo Empty
else
    echo Not Empty
fi
1

Я думаю, что лучшее решение:

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

спасибо https://stackoverflow.com/a/91558/520567

Это анонимное редактирование моего ответа, которое может кому-то пригодиться или не пригодиться. Небольшое изменение дает количество файлов:

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

Это будет работать правильно, даже если имена файлов содержат пробелы.

0

Как насчет тестирования, если каталог существует и не пуст в одном операторе if?

if [[ -d path/to/dir && -n "$(ls -A path/to/dir)" ]]; then 
  echo "directory exists"
else
  echo "directory doesn't exist"
fi
0

Это все здорово - просто превратил его в скрипт, чтобы я мог проверять наличие пустых каталогов ниже текущего. Нижеследующее должно быть помещено в файл с именем 'findempty', где-то помещен в путь, чтобы bash мог найти его и затем запустить chmod 755. Я думаю, можно легко изменить ваши специфические потребности.

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

Это работает для меня, чтобы проверить и обработать файлы в каталоге ../IN , учитывая, что скрипт находится в ../Script directory:

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
-1

Для любого каталога, кроме текущего, вы можете проверить, является ли он пустым, попытавшись выполнить rmdir , потому что rmdir гарантированно завершится с ошибкой для непустых каталогов. Если rmdir успешно, и вы действительно хотели, чтобы пустой каталог выдержал тест, просто mkdir еще раз.

Не используйте этот хак, если есть другие процессы, которые могут стать некомпетентными из-за каталога, который, как они знают, ненадолго прекратит свое существование.

Если rmdir не будет работать для вас, и вы можете тестировать каталоги, которые могут содержать большое количество файлов, любое решение, основанное на глобализации оболочки, может работать медленно и / или работать с ограничениями длины командной строки. Вероятно, лучше использовать find в этом случае. Самое быстрое решение для find я могу придумать, идет как

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

Это работает для GNU и BSD версий find но не для Solaris, в которой отсутствуют все эти операторы find . Люблю свою работу, Оракул.

-3

Вы можете попытаться удалить каталог и дождаться ошибки; rmdir не удалит каталог, если он не пуст.

_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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .