Как из сценария оболочки проверить, есть ли в каталоге файлы?
Что-то похожее на это
if [ -e /some/dir/* ]; then echo "huzzah"; fi;
но это работает, если каталог содержит один или несколько файлов (указанный выше работает только с 0 или 1 файлом).
Как из сценария оболочки проверить, есть ли в каталоге файлы?
Что-то похожее на это
if [ -e /some/dir/* ]; then echo "huzzah"; fi;
но это работает, если каталог содержит один или несколько файлов (указанный выше работает только с 0 или 1 файлом).
Ответы:
Решения, которые до сих пор используют ls . Вот решение для всех bash:
#!/bin/bash
shopt -s nullglob dotglob # To include hidden files
files=(/some/dir/*)
if [ ${#files[@]} -gt 0 ]; then echo "huzzah"; fi
shopt -q nullglob || resetnullglob=1; shopt -s nullglob; shopt -q dotglob || resetdotglob=1; shopt -s dotglob; files=(/some/dir/*); [ "$files" ] && echo "wowzers"; [ "$resetdotglob" ] && shopt -u dotglob; [ "$resetnullglob" ] && shopt -u nullglob;
files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*)
files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*) тогда оператор if должен измениться на if [ ${#files} -gt 0 ];или, может быть, вы просто забыли () вокруг команды вспомогательной оболочки? files=($(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*))
shopt -s nullglob dotglob; f=your/dir/*; ((${#f}))Этот трюк 100% bashи вызывает (порождает) суб-оболочку. Идея принадлежит Bruno De Fraine и улучшена комментарием teambob .
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 для 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)" ]Этот трюк основан на статье nixCraft, опубликованной в 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
или однострочная версия башизма:
[[ $(ls -A your/dir) ]] && echo "contains files" || echo "empty"
Примечание: ls возвращается, $?=2когда каталог не существует. Но никакой разницы между файлом и пустым каталогом.
[ -n "$(find your/dir -prune -empty)" ]Этот последний трюк основан на ответе gravstar, где -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
Этот последний код работает в большинстве случаев, но имейте в виду, что вредоносные пути могут выражать команду ...
[ -n "$(find "your/dir" -prune -empty)" ], чтобы избежать повторения пути к каталогу.
if [ ``ls -A your/dir`` ]в сценарии я пришел к выводу, что он отлично работает для каталога с 0, 1 или 2 подкаталогами, но не работает для каталога с более чем 2 подкаталогами. line 17: [: 20150424-002813: unary operator expectedгде 20150424-002813было одно из имен каталогов. Используемый снаряд был /bin/bash/. Я наконец поменял его наls "$destination" | tail -1
if [ ``ls -A my/dir`` ]выходит по ошибке bash: [: -A: binary operator expected. Проверено на bash версий 4.1.2 и 4.2.53.
-nвариант был в заголовке, а затем не в нижеследующем абзаце). Так что да, все в порядке.
ls: cannot access '/path': No such file or directory. Есть ли способ подавить это сообщение? Я бы хотел там молча потерпеть неудачу.
Как насчет следующего:
if find /some/dir/ -maxdepth 0 -empty | read v; then echo "Empty dir"; fi
Таким образом, нет необходимости создавать полный список содержимого каталога. Это readодновременно и отбрасывает вывод, и делает выражение истинным только тогда, когда что-то читается (т. /some/dir/Е. Обнаруживается пустым find).
find /some/dir/ -maxdepth 0 -empty -exec echo "huzzah" \;
lsвывода и не полагается на функции оболочки, отличные от стандартных.
-maxdepthи -emptyпервичные цвета.
Пытаться:
if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi
/bin/ls <some_dir>/* 2> /dev/nullif [! -z "$ tmp"]; then echo Something is there fi
ls /some/dir/*]; затем эхо "ура"; fi
-nвместо ! -z(они оба эквивалентны, но почему бы не использовать более короткую форму, если она существует).
BigGray% if [ ! -z ls / some / dir / * `]; затем эхо "ура"; fi zsh: совпадений не найдено: / some / dir / * `
ls...в bash
# 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
}
DIR="/some/dir"
if [ "$(ls -A $DIR)" ]; then
echo 'There is something alive in here'
fi
# Проверяет, содержит ли каталог какие-либо не скрытые файлы.
#
# использование: если пусто "$ HOME"; затем эхо «Добро пожаловать домой»; фи
#
пусто() {
для _ief в $ 1 / *; делать
если [-e "$ _ief"]; затем
возврат 1
фи
сделано
возврат 0
}
Некоторые примечания по реализации:
forЦикл избегает вызов внешнего lsпроцесса. Он по-прежнему считывает все записи каталога один раз. Это можно оптимизировать, только написав программу на C, которая явно использует readdir ().test -eВнутри цикла ловит случай пустой каталог, в этом случае переменная _iefбудет присвоено значение «somedir / *». Только если этот файл существует, функция вернет "непустой"testреализация не поддерживает -eфлаг.dotglobне установлено -shopt -s dotglob
Это говорит мне, пуст ли каталог или нет, количество файлов, которые он содержит.
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
ls .
Это может быть очень поздний ответ, но вот решение, которое работает. Эта строка распознает только наличие файлов! Это не даст вам ложного срабатывания, если каталоги существуют.
if find /path/to/check/* -maxdepth 0 -type f | read
then echo "Files Exist"
fi
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от ш Рича (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).
is_empty(){ [ ! -d "${1}" ] && return 2;set -- "${1}" "${1}"/* "${1}"/.[!.]* "${1}"/..?*;[ "${*}" = "${1} ${1}/* ${1}/.[!.]* ${1}/..?*" ]; };
Я знаю, что вопрос был помечен как 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)совпадения: не каталог ИЛИ пуст. Таким образом, в (^F)одиночку также будут перечислены, например, обычные файлы. Таким образом, как объясняется на 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)квалификатора glob:
$ mkdir Y
$ touch Y/.f
$ for i in Y(N/^F) ; do echo $i ; done ; echo "finished"
finished
Таким образом, для пустых каталогов нам нужен квалификатор (N/^F), который можно читать как «не предупреждать меня о сбоях, каталогах, которые не заполнены».
Точно так же для непустых каталогов нам нужен квалификатор (NF), который мы можем также читать как: «не предупреждать меня о сбоях, полные каталоги».
Я удивлен, что руководство 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: Нет такого файла или каталога, хотя на самом деле такой тест не требуется.
Небольшой вариант ответа Бруно :
files=$(ls -1 /some/dir| wc -l)
if [ $files -gt 0 ]
then
echo "Contains files"
else
echo "Empty"
fi
Меня устраивает
Взяв подсказку (или несколько) из ответа 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), но в худшем случае она линейна по размеру каталога. Я этого не измерял.
До сих пор я не видел ответа с использованием grep, который, я думаю, дал бы более простой ответ (не слишком много странных символов!). Вот как я могу проверить, существуют ли какие-либо файлы в каталоге, используя оболочку bourne:
это возвращает количество файлов в каталоге:
ls -l <directory> | egrep -c "^-"
вы можете указать путь к каталогу, в который записан каталог. Первая половина вертикальной черты гарантирует, что первым символом вывода будет «-» для каждого файла. Затем egrep подсчитывает количество строк, начинающихся с этого символа, используя регулярные выражения. теперь все, что вам нужно сделать, это сохранить полученное число и сравнить его, используя обратные кавычки, например:
#!/bin/sh
fileNum=`ls -l <directory> | egrep -c "^-"`
if [ $fileNum == x ]
then
#do what you want to do
fi
x - это переменная по вашему выбору.
Простой ответ с помощью bash :
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
Просто в нем режиссеры:
$ 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
С помощью некоторого обходного пути я мог найти простой способ узнать, есть ли файлы в каталоге. Это может быть расширено с помощью команд 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
if ls /some/dir/* >/dev/null 2>&1 ; then echo "huzzah"; fi;
nullglob, потому что тогда lsкоманда будет успешной.
для тестирования определенного целевого каталога
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;
Попробуйте с помощью команды find. Укажите каталог жестко или в качестве аргумента. Затем запустите find для поиска всех файлов внутри каталога. Проверьте, является ли возвращение find нулевым. Эхо данных находки
#!/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
Мне не нравится ls - A решения. Скорее всего, вы хотите проверить, пуст ли каталог, потому что вы не хотите его удалять. Следующее делает это. Однако, если вы просто хотите зарегистрировать пустой файл, конечно, его удаление и воссоздание будет быстрее, чем перечисление, возможно, бесконечных файлов?
Это должно работать ...
if ! rmdir ${target}
then
echo "not empty"
else
echo "empty"
mkdir ${target}
fi
${target}/...
Для меня это хорошо работает (когда существует каталог):
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