Проверка с помощью сценария командной строки, содержит ли каталог файлы

StackOverflow https://stackoverflow.com/questions/91368

  •  01-07-2019
  •  | 
  •  

Вопрос

Как с помощью сценария оболочки проверить, содержит ли каталог файлы?

Что-то похожее на это

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

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

Это было полезно?

Решение

Решения, которые до сих пор используют ls.Вот универсальное решение:

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

Другие советы

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


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

Этот трюк на 100% bash и вызывает (порождает) вспомогательную оболочку.Идея взята из Бруно Де Фрейн и улучшен за счет тимбобкомментарий автора.

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

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

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

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

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

или однострочная версия bashism:

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

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


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

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

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

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

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

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

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

Попробуй:

if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi
# 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
}

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

ИМО, лучшее решение - это то, которое использует

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

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

 ls -A /some/dir | wc -l
# 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 процесс.Он по-прежнему считывает все записи каталога один раз.Это можно оптимизировать, только написав программу на языке Си, которая явно использует readdir().
  • Тот Самый test -e внутри цикла улавливается случай пустого каталога, и в этом случае переменная _ief было бы присвоено значение "somedir/*".Только если этот файл существует, функция вернет "непустой"
  • Эта функция будет работать во всех реализациях POSIX.Но имейте в виду, что Solaris /bin / sh не подпадает под эту категорию.Его test реализация не поддерживает -e Отметить.

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

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

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

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

Я удивлен, что руководство wooledge по пустым каталогам об этом не упоминалось.Это руководство, как и весь wooledge в целом, обязательно к прочтению для ответов на вопросы типа shell.

Примечательно с этой страницы:

Никогда не пытайтесь анализировать выходные данные 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:./*.миль на галлон:Нет такого файла или каталога, хотя на самом деле никакой проверки не требуется. такой тест не требуется.

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+ файлами прошло не так уж медленно), будет использовать, по крайней мере, достаточно памяти, чтобы выделить все каталоги / имена файлов (и многое другое), поскольку все они передаются (разрешаются) функции в качестве аргументов, некоторые оболочки, вероятно, имеют ограничения на количество аргументов и / или длину аргументов.

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

Обновить

Приведенная выше версия не учитывает скрытые файлы / каталоги, на случай, если потребуется еще какой-то тест, например is_empty От Трюки Рича с sh (POSIX shell):

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).

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

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

У меня это работает

ЗШ

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

Тест на наличие непустого каталога

Чтобы проверить, есть ли 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) определитель глобуса (см. 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) Матчи:не является каталогом ИЛИ является пустым.Таким образом, (^F) alone также будет содержать список обычных файлов, например.Таким образом, как объяснено на 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) ("пустые каталоги") и, таким образом, выдает сообщение об ошибке, в котором говорится, что совпадения для глобуса не найдены.Поэтому нам необходимо подавить эти возможные сообщения об ошибках с помощью (N) определитель глобуса:

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

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

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

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

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

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

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

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

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

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

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

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

это работает и для путей с пробелами

Простой ответ с помощью удар:

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

Я бы пошел на 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

Просто dirs в нем:

$ 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

Попробуйте с помощью команды find.Укажите жестко заданный каталог или в качестве аргумента.Затем запустите команду find для поиска по всем файлам внутри каталога.Проверьте, является ли возвращаемое значение find равным null.Повторите данные поиска

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

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

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

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

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

чтобы протестировать определенный целевой каталог

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;

У меня это хорошо работает (когда существует 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top