Проверка с помощью сценария командной строки, содержит ли каталог файлы
Вопрос
Как с помощью сценария оболочки проверить, содержит ли каталог файлы?
Что-то похожее на это
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