У меня есть требование, если я выполняю скрипт ./123
с аргументами пустого пути, скажем /usr/share/linux-headers-3.16.0-34-generic/.tmp_versions
(этот каталог пуст). Должен отображаться «каталог пуст»
Мой код:
#!/bin/bash
dir="$1"
if [ $# -ne 1 ]
then
echo "please pass arguments"
exit
fi
if [ -e $dir ]
then
printf "minimum file size: %s\n\t%s\n" \
$(du $dir -hab | sort -n -r | tail -1)
printf "maximum file size: %s\n\t%s\n" \
$(du $dir -ab | sort -n | tail -1)
printf "average file size: %s"
du $dir -sk | awk '{s+=$1}END{print s/NR}'
else
echo " directory doesn't exists"
fi
if [ -d "ls -A $dir" ]
then
echo " directory is empty"
fi
У меня появляется сообщение об ошибке, например, если я выполняю имя скрипта ./123 /usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
(этот каталог пуст).
minimum file size: 4096
/usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
maximum file size: 4096
/usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
average file size: 4
вместо вывода только «директория пуста» показывает вывод выше
Приведенный ниже вывод должен отображаться, если я превышаю сценарий с правильными аргументами (я имею в виду с правильным путем к каталогу). сказать./123 /usr/share
minimum file size: 196
/usr/share
maximum file size: 14096
/usr/share
average file size: 4000
мой ожидаемый результат: ./123 /usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
directory is empty.
shell-script
будда срикант
источник
источник
Ответы:
Выше приведен тест POSIX-совместимый, и он должен быть очень быстрым.
ls
будут перечислены все файлы / каталоги в директории исключая.
и..
каждый из них в каждой строке и-q
Цитата все непечатаемые символы (в том числе\n
ewlines) на выходе с?
вопросительным знаком. Таким образом, еслиgrep
получит хотя бы один символ на входе, он вернет true, иначе false.Чтобы сделать это только в POSIX-оболочке:
POSIX-оболочка (которая не ранее отключило
-f
поколение ilename) будет массив позиционно-параметр либо буквальной строке с последующей командой выше, либо к полям , порожденные операторами Глобы в конце каждого из них. Будет ли это так, зависит от того, соответствуют ли глобусы чему-либо. В некоторых оболочках вы можете указать неразрешимому глобу расширяться до нуля - или вообще ничего. Иногда это может быть полезно, но оно не переносимо и часто сопряжено с дополнительными проблемами, такими как необходимость установки специальных параметров оболочки и их последующего сброса.set
"$@"
set
Единственным переносимым средством обработки аргументов с нулевыми значениями являются пустые или неустановленные переменные или
~
расширения тильды. И последнее, кстати, намного безопаснее, чем первое.Выше оболочки только проверяет любой из файлов на
-e
наличие, если ни один из трех указанных глобусов не разрешает более одного совпадения. Таким образом,for
цикл запускается только для трех или менее итераций, и только в случае пустой директории или в случае, если один или несколько шаблонов разрешаются только в один файл.for
Такжеbreak
S , если любой из комков представляет фактический файл - и , как я расположил шарики в порядке , скорее всего, не менее вероятно, он должен в значительной степени выйти на первую итерацию каждый раз.В любом случае это должно включать только один системный
stat()
вызов - оболочку, иls
оба должны толькоstat()
запрашивать каталог и перечислять файлы, содержащиеся в отчете его dentries . Это контрастирует с поведением,find
которое вместоstat()
каждого файла вы можете перечислить с ним.источник
ls
делу. и[
молчат, когда у них нет доступа. Например,[ -e /var/spool/cron/crontabs/stephane ]
будет молча сообщать о ложном, пока есть файл с таким именем.С GNU или современными BSD
find
вы можете делать:(предполагается , что
$dir
не выглядит какfind
предикат (!
,(
,-name...
).POSIXly:
источник
[-z $dir ]
жалуется, что в[-z
большинстве систем не вызывается команда . Вам нужны пробелы вокруг скобок .[ -z $dir ]
бывает true, еслиdir
пусто, и false для большинства других значенийdir
, но это ненадежно, например, это правда, если значениеdir
is= -z
или-o -o -n -n
. Всегда используйте двойные кавычки вокруг подстановок команд (это относится и к остальной части вашего скрипта).[ -z "$dir" ]
проверяет, является ли значение переменнойdir
пустым Значением переменной является строка, которая является путем к каталогу. Это ничего не говорит вам о самом каталоге.Нет оператора для проверки того, является ли каталог пустым, как для обычного файла (
[ -s "$dir" ]
верно для каталога, даже если он пуст). Простой способ проверить, является ли каталог пустым, состоит в перечислении его содержимого; если вы получите пустой текст, каталог будет пустым.На старых системах, которые не имеют
ls -A
, вы можете использоватьls -a
, но тогда.
и..
перечислены.(Не делайте отступ строки, начинающейся с,
..
поскольку строка должна содержать только новую строку, а не новую и лишний пробел.)источник
$(…)
- командная заменаВы смотрите на атрибуты самого каталога.
Вы хотите посчитать, сколько файлов там:
Итак, тест для «каталога пуст»:
Как это:
источник
Мой ответ tldr:
Он совместим с POSIX и, что не имеет большого значения, обычно быстрее, чем решение, которое выводит каталог и передает вывод в grep.
Использование:
Мне нравится ответ https://unix.stackexchange.com/a/202276/160204 , который я переписываю как:
Он перечисляет каталог и передает результат в grep. Вместо этого я предлагаю простую функцию, основанную на расширении и сравнении глобусов.
Эта функция не является стандартной POSIX и вызывает подоболочку с
$()
. Сначала я объясню эту простую функцию, чтобы мы могли лучше понять окончательное решение (см. Ответ tldr выше) позже.Объяснение:
Левая сторона (LHS) пуста, когда не происходит расширения, что является случаем, когда каталог пуст. Опция nullglob обязательна, потому что в противном случае, когда нет совпадения, сам шар является результатом расширения. (Наличие RHS, совпадающего с глобусами LHS, когда каталог пуст, не работает из-за ложных срабатываний, возникающих, когда глобус LHS соответствует одному файлу с именем самого глобуса:
*
глобус соответствует подстроке*
в имени файла. ) Выражение скобки{,.[^.],..?}
охватывает скрытые файлы, но не..
или.
.Поскольку
shopt -s nullglob
выполняется внутри$()
(подоболочка), это не меняетnullglob
опцию текущей оболочки, что обычно хорошо. С другой стороны, это хорошая идея, чтобы установить эту опцию в сценариях, потому что склонен к ошибке, когда глобус возвращает что-то, когда нет совпадения. Таким образом, можно установить опцию nullglob в начале скрипта, и она не понадобится в функции. Давайте помнить об этом: нам нужно решение, которое работает с опцией nullglob.Предостережения:
Если у нас нет доступа для чтения к каталогу, функция выдает сообщение так же, как если бы был пустой каталог. Это относится также к функции, которая перечисляет каталог и grep выводит.
Команда
shopt -s nullglob
не стандартная POSIX.Он использует подоболочку, созданную
$()
. Это не имеет большого значения, но хорошо, если мы можем избежать этого.Pro:
Не то чтобы это действительно имеет значение, но эта функция в четыре раза быстрее, чем предыдущая, измеряемая количеством процессорного времени, проведенного в ядре внутри процесса.
Другие решения:
Мы можем удалить ноны POSIX
shopt -s nullglob
команды на LHS и поместите строку"$1/* $1/.[^.]* $1/..?*"
в RHS и устранить отдельно ложные срабатывания , которые возникают , когда у нас есть только файлы с именем'*'
,.[^.]*
или..?*
в каталоге:Без
shopt -s nullglob
команды теперь имеет смысл удалить подоболочку, но мы должны быть осторожны, потому что мы хотим избежать разбиения слов и все же разрешить расширение глобуса на LHS. В частности, цитирование во избежание разбиения слов не работает, поскольку оно также предотвращает расширение глобуса. Наше решение состоит в том, чтобы рассматривать шарики отдельно:У нас все еще есть разделение слов для отдельного глобуса, но теперь все нормально, потому что это приведет к ошибке, только если каталог не пуст. Мы добавили 2> / dev / null, чтобы отменить сообщение об ошибке, когда на LHS есть много файлов, соответствующих данному глобу.
Напомним, что нам нужно решение, которое работает и с опцией nullglob. Вышеупомянутое решение завершается ошибкой с параметром nullglob, потому что, когда каталог пуст, LHS также пуст. К счастью, это никогда не говорит, что каталог пуст, когда это не так. Он только не может сказать, что он пуст, когда он есть. Таким образом, мы можем управлять опцией nullglob отдельно. Мы не можем просто добавлять случаи
[ "$1/"* = "" ]
и т. Д., Поскольку они будут расширяться как[ = "" ]
и т. Д., Которые синтаксически некорректны Таким образом, мы используем[ "$1/"* "" = "" ]
и т.д. вместо этого. Мы снова должны рассмотреть три случая*
,..?*
и.[^.]*
в соответствии скрытые файлы, но не.
и..
, Они не будут мешать, если у нас нет опции nullglob, потому что они также никогда не говорят, что она пуста, когда ее нет. Итак, окончательное предлагаемое решение:Проблема безопасности:
Создайте два файла
rm
иx
в пустой директории и выполните*
в приглашении. Глобус*
расширится доrm x
и будет выполнен для удаленияx
. Это не проблема безопасности, потому что в нашей функции глобусы расположены там, где расширения рассматриваются не как команды, а как аргументы, как вfor f in *
.источник
$(set -f; echo "$1"/*)
кажется довольно сложным способом написания"$1/*"
. И это не будет соответствовать скрытым каталогам или файлам."$1/*"
(обратите внимание, что в кавычках*
), поэтому для негоset -f
не нужны , в частности, и subshell ../* ./.[!.]* ./..?*
). Может быть, вы можете включить это, чтобы сделать функцию завершенной.Вот еще один простой способ сделать это. Предположим, что D - это полный путь к каталогу, который вы хотите проверить на пустоту.
потом
Это работает, потому что
имеет в качестве выхода
awk удаляет D и если размер равен 0, каталог пуст.
источник
источник
echo
, все, что вам нужно, этоlist="$somedir/*"
. Кроме того, это сложно и подвержено ошибкам. Вы не упомянули, что ОП должен указать путь к целевому каталогу, включая, например, косую черту.