Проверка из оболочки script, если каталог содержит файлы

Из оболочки script, как проверить, содержит ли каталог файлы?

Нечто похожее на это

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

но работает, если каталог содержит один или несколько файлов (вышеупомянутый работает только с точно 0 или 1 файлом).

Ответ 1

Решения до сих пор используют ls. Здесь все bash решение:

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

Ответ 2

Три лучших трюка


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

Этот трюк является 100% bash и вызывает (порождает) ад -s ад. Идея взята из Bruno De Fraine и улучшена комментарием в теамбобе.

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

Примечание: нет никакой разницы между пустым каталогом и несуществующим (и даже если предоставленный путь является файлом).

Существует аналогичная альтернатива и более подробная информация (и больше примеров) по "официальному" FAQ для #bash IRC-канала:

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

Этот трюк вдохновлен статьей nixCraft, опубликованной в 2007 году. Добавьте 2>/dev/null чтобы подавить ошибку вывода "No such file or directory".
См. Также Andrew Taylor answer (2008) и gr8can8dian answer (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

или однострочный башизм:

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

Примечание: ls возвращает $?=2 когда каталог не существует. Но никакой разницы между файлом и пустым каталогом.


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

Этот последний трюк вдохновлен ответом Grastar, где -maxdepth 0 заменяется на -prune и улучшен комментарием phils.

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

вариация с использованием -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

Объяснение:

  • find -prune подобен, чем find -maxdepth 0 используя меньше символов
  • find -empty печатает пустые каталоги и файлы
  • find -type d только каталоги отпечатков

Примечание. Вы также можете заменить [ -n "$(find your/dir -prune -empty)" ] только сокращенной версией ниже:

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

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

Ответ 3

Как насчет следующего:

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

Таким образом, нет необходимости в создании полного списка содержимого каталога. read - это отбрасывать вывод и делать выражение справедливым только тогда, когда что-то читается (т.е. /some/dir/ оказывается пустым на find).

Ответ 4

Try:

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

Ответ 5

Будьте осторожны с каталогами с большим количеством файлов! Для вычисления команды ls может потребоваться некоторое время.

IMO лучшим решением является тот, который использует

find /some/dir/ -maxdepth 0 -empty

Ответ 6

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

Ответ 7

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

Ответ 8

Не могли бы вы сравнить результаты этого?

 ls -A /some/dir | wc -l

Ответ 9

# Checks whether a directory contains any nonhidden files.
#
# usage: if isempty "$HOME"; then echo "Welcome home"; fi
#
isempty() {
    for _ief in $1/*; do
        if [ -e "$_ief" ]; then
            return 1
        fi
    done
    return 0
}

Некоторые примечания по реализации:

  • Цикл for позволяет избежать вызова внешнего процесса ls. Он по-прежнему читает все записи каталога один раз. Это можно только оптимизировать, написав программу на C, которая явно использует readdir().
  • test -e внутри цикла попадает в случай пустого каталога, и в этом случае переменной _ief присваивается значение "somedir/*". Только если этот файл существует, функция вернет "непустую"
  • Эта функция будет работать во всех реализациях POSIX. Но имейте в виду, что Solaris/bin/sh не попадает в эту категорию. Его реализация test не поддерживает флаг -e.

Ответ 10

Это говорит мне, что каталог пуст или нет, количество файлов, которое оно содержит.

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

Ответ 11

Это может быть очень поздний ответ, но вот решение, которое работает. Эта строка распознает только существование файлов! Это не даст вам ложного позитива, если существуют каталоги.

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

Ответ 12

Я удивлен, что руководство по wooledge на пустых каталогах не упоминалось. Это руководство, и все из wooledge действительно, должны читать для вопросов типа оболочки.

Из этой страницы следует отметить:

Никогда не пытайтесь разобрать вывод ls. Даже решения ls -A могут сломаться (например, на HP-UX, если вы root, ls -A делает полная противоположность тому, что он делает, если вы не root - и нет, я не могу составить что-то, что невероятно глупый).

На самом деле, возможно, вы захотите избежать прямого вопроса. Обычно люди хотят знать, каталог пуст, потому что он хочет что-то делать с файлами в нем и т.д. Посмотрите на большую вопрос. Например, один из этих примеров на основе поиска может быть подходящим решением:

   # 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

Чаще всего все, что действительно необходимо, это примерно так:

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

Другими словами, человек, задающий вопрос, мог подумать, что явный тест пустой директории необходимо избегать сообщения об ошибке, например mympgviewer:./*.mpg: нет такого файла или каталога, если на самом деле нет такой тест необходим.

Ответ 13

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

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

Предположим, у вас нет файла с именем * в /any/dir/you/check, он должен работать на bash dash posh busybox sh и zsh, но (для zsh) требуется unsetopt nomatch.

Спектакли должны быть сопоставимы с любым ls, который использует * (glob), я думаю, будет медленным в каталогах со многими узлами (мой /usr/bin с 3000+ файлами пошел не так медленно), будет использовать как минимум достаточно памяти для размещения всех dirs/filenames (и более), поскольку все они передаются (разрешены) функции как аргументы, у некоторой оболочки, вероятно, есть ограничения на количество аргументов и/или длину аргументов.

Портативный быстрый способ O (1) zero resources, чтобы проверить, является ли каталог пустым, было бы неплохо иметь.

Обновление

В приведенной выше версии не учитываются скрытые файлы /dirs, если требуется еще один тест, например is_empty из Richs sh (оболочка POSIX ) трюки:

is_empty () (
cd "$1"
set -- .[!.]* ; test -f "$1" && return 1
set -- ..?* ; test -f "$1" && return 1
set -- * ; test -f "$1" && return 1
return 0 )

Но вместо этого я думаю о чем-то вроде этого:

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

Некоторая забота о трейлинг-слэшах отличается от аргумента и вывода find, когда каталог пуст, и завершающие символы новой строки (но это должно быть легко обрабатываться), к сожалению, на моем busybox sh показано, что, вероятно, является ошибкой на трубке find -> dd с усеченным результатом случайным образом (если я использовал cat, вывод всегда один и тот же, кажется, dd с аргументом count).

Ответ 14

Небольшое отклонение Ответ Бруно:

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

Это работает для меня

Ответ 15

ЗШ

Я знаю, что вопрос был отмечен для bash; но, только для справки, для пользователей zsh:

Тестирование для непустого каталога

Чтобы проверить, не является ли foo:

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

где, если foo является пустым, код в блоке for будет выполнен.

Тест для пустого каталога

Чтобы проверить, пуст ли foo:

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

где, если foo пуст, код в блоке for будет выполнен.

Заметки

Нам не нужно было указывать каталог foo выше, но мы можем сделать это, если нам нужно:

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

Мы также можем тестировать несколько объектов, даже если это не каталог:

$ 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

Все, что не является каталогом, просто игнорируется.

Дополнительно

Поскольку мы глотаем, мы можем использовать любой глобус (или расширение скобки):

$ 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

Мы также можем исследовать объекты, которые помещаются в массив. С такими каталогами, как указано выше, например:

$ 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

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

Обратите внимание, что код в блоке for, очевидно, выполняется в каждом каталоге по очереди. Если это нежелательно, вы можете просто заполнить параметр массива, а затем работать с этим параметром:

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

объяснение

Для пользователей zsh существует (F) glob-квалификатор (см. man zshexpn), который соответствует "полным" (непустым) каталогам:

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

В квалификаторе (F) перечислены объекты, которые соответствуют: - это каталог И не пуст. Итак, (^F) соответствует: не каталог OR пуст. Таким образом, (^F) самостоятельно также будет перечислять обычные файлы, например. Таким образом, как поясняется на man-странице zshexp, нам также нужен (/) glob-классификатор, в котором перечислены только каталоги:

$ 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

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

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

и просто чтобы убедиться, что непустой каталог не будет захвачен:

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

К сожалению! Поскольку Y не пуст, zsh не находит совпадений для (/^F) ("каталоги, которые пусты") и, таким образом, выплевывает сообщение об ошибке, в котором говорится, что совпадений для glob не найдено. Поэтому нам необходимо подавить эти возможные сообщения об ошибках с помощью классификатора (N) glob:

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

Таким образом, для непустых каталогов нам нужен определитель (N/^F), который вы можете прочитать как "не предупреждайте меня о сбоях, каталоги, которые не полны".

Аналогично, для пустых каталогов нам нужен определитель (NF), который мы также можем читать как: "не предупреждайте меня о сбоях, полных каталогах".

Ответ 16

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

Ответ 17

До сих пор я не видел ответа, который использует grep, который, я думаю, даст более простой ответ (с не слишком большим количеством странных символов!). Вот как я бы проверьте, существуют ли какие-либо файлы в каталоге с использованием оболочки bourne:

это возвращает количество файлов в каталоге:

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

вы можете заполнить путь к каталогу, в котором написана директория. Первая половина трубы гарантирует, что первый символ вывода "-" для каждого файла. egrep затем подсчитывает количество строк, начинающихся с этого символ с использованием регулярных выражений. теперь все, что вам нужно сделать, это сохранить номер, который вы получите, и сравнить его с помощью backquotes, например:

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

x - это переменная по вашему выбору.

Ответ 18

Смешивая мелочи и последние ответы, я добрался до

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

который также работает для путей с пробелами

Ответ 19

Простой ответ с bash:

if [[ $(ls /some/dir/) ]]; then echo "huzzah"; fi;

Ответ 20

Я бы пошел за find:

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

Это проверяет вывод поиска только файлов в каталоге, не просматривая подкаталоги. Затем он проверяет вывод с помощью опции -z, взятой из man test:

   -z STRING
          the length of STRING is zero

Смотрите некоторые результаты:

$ mkdir aaa
$ dir="aaa"

Пустой каталог:

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

Просто в нем:

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

Файл в каталоге:

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

Файл в подкаталоге:

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

Ответ 21

Попробуйте найти команду. Укажите каталог hardcoded или как аргумент. Затем инициируйте поиск для поиска всех файлов внутри каталога. Проверьте, является ли возврат поиска нулевым. Повторите данные поиска

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

Ответ 22

С некоторым обходным путем я мог найти простой способ узнать, есть ли файлы в каталоге. Это может быть расширено с помощью команд grep для проверки файлов.xml или.txt и т.д. Ex: ls/some/dir | grep xml | wc -l | grep -w "0" 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

Ответ 23

Взяв подсказку (или несколько) из olibre ответа, мне нравится функция Bash:

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

Потому что, хотя он создает одну подоболочку, он настолько близок к решению O (1), насколько я могу себе представить, и присвоение ему имени делает его читабельным. Я могу тогда написать

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

Что касается O (1), то существуют случайные случаи: если в большом каталоге были удалены все или все элементы, кроме последней, "find", возможно, придется прочитать всю вещь, чтобы определить, пуста ли она. Я полагаю, что ожидаемая производительность равна O (1), но наихудший случай - линейный размер каталога. Я не измерял это.

Ответ 24

Мне не нравятся размещенные решения ls - A. Скорее всего, вы хотите проверить, пуст ли каталог, потому что вы не хотите его удалять. Это делает следующее. Если, однако, вы просто хотите зарегистрировать пустой файл, наверняка удаляете и воссоздаете его быстрее, чем перечисляете, возможно, бесконечные файлы?

Это должно работать...

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

Ответ 25

для проверки конкретного целевого каталога

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;

Ответ 26

Хорошо работает для меня это (когда существует dir):

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

С полной проверкой:

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