Если я хочу проверить наличие одного файла, я могу проверить его с помощью test -e filename
или [ -e filename ]
.
Предположим, у меня есть глобус, и я хочу знать, существуют ли какие-либо файлы, имена которых соответствуют глобусу. Глобус может соответствовать 0 файлам (в этом случае мне ничего не нужно делать), или он может соответствовать 1 или более файлам (в этом случае мне нужно что-то делать). Как я могу проверить, есть ли у шара какие-либо совпадения? (Мне все равно, сколько совпадений, и было бы лучше, если бы я мог сделать это с одним if
оператором и без циклов (просто потому, что я считаю это наиболее читабельным).
( test -e glob*
не удается, если глобус соответствует более чем одному файлу.)
Ответы:
Побег шаблон или он будет предварительно расширен в спички.
Статус выхода:
stdout
список файлов , соответствующих Glob .Я думаю, что это лучший вариант с точки зрения краткости и минимизации потенциальных побочных эффектов.
ОБНОВЛЕНИЕ : пример использования запрашивается.
источник
compgen
это специфичная для bash встроенная команда, которая не является частью стандартных встроенных команд оболочки Unix, определенных в POSIX. pubs.opengroup.org/onlinepubs/9699919799 pubs.opengroup.org/onlinepubs/9699919799/utilities/… Поэтому не используйте его в сценариях, где переносимость на другие оболочки является проблемой.if ls /tmp/*Files 2>&1 >/dev/null; then echo exists; fi
- может быть полезно для кода гольф? Сбой, если есть файл с именем, совпадающим с глобаном, которому глобус не должен был соответствовать, но в этом случае у вас, вероятно, большие проблемы.if ls /tmp/*Files &> /dev/null; then echo exists; fi
compgen
см.man bash
Или сhelp compgen
Параметр оболочки nullglob - это действительно башизм.
Чтобы избежать необходимости утомительного сохранения и восстановления состояния nullglob, я бы установил его только в подоболочке, которая расширяет глобус:
Для лучшей переносимости и большей гибкости используйте find:
Явный действия -print -quit используются для поиска вместо неявного действия -print по умолчанию, поэтому поиск будет завершен, как только будет найден первый файл, соответствующий критериям поиска. В случае совпадения большого количества файлов это должно выполняться намного быстрее, чем
echo glob*
или,ls glob*
и это также исключает возможность чрезмерного заполнения расширенной командной строки (некоторые оболочки имеют ограничение в 4 КБ).Если find кажется излишним и число файлов, которые могут совпадать, невелико, используйте stat:
источник
find
кажется, совершенно правильно. У него нет угловых случаев, поскольку оболочка не выполняет расширение (и не передает нерасширенный глобус какой-либо другой команде), она переносима между оболочками (хотя, очевидно, не все параметры, которые вы используете, указаны в POSIX), и она быстрее, чемls -d glob*
(предыдущий принятый ответ), потому что он останавливается, когда достигает первого совпадения.shopt -u failglob
как эти параметры могут как-то конфликтовать.find
Решение будет соответствовать файлу без Глоб символов , а также. В этом случае это то, что я хотел. Просто кое-что знать, хотя.-maxdepth
опцию для поиска POSIX.источник
nullglob
вместо проверки, чтобы увидеть, равен ли один результат самому шаблону. Некоторые шаблоны могут соответствовать именам, которые в точности совпадают с самим шаблоном (напримерa*b
, но неa?b
или[a]
).touch '*py'
), но это указывает мне другое хорошее направление."$M"
его для сокращения"${M[0]}"
. В противном случае, у вас уже есть расширение glob в переменной массива, так что вы gtg для передачи его другим вещам в виде списка, вместо того, чтобы заставлять их повторно расширять glob.[
процесса) сif [[ $M ]]; then ...
мне нравиться
Это и удобочитаемо, и эффективно (если нет огромного количества файлов).
Основным недостатком является то, что это гораздо тоньше, чем кажется, и я иногда вынужден добавить длинный комментарий.
Если есть совпадение,
"glob*"
он расширяется оболочкой, и все совпадения передаютсяexists()
, который проверяет первое и игнорирует остальные.Если нет совпадений,
"glob*"
передаетсяexists()
и обнаруживаются, что их там тоже не существует.Изменить: может быть ложное срабатывание, см. Комментарий
источник
*.[cC]
(может быть, не файлc
илиC
файл, но файл называется*.[cC]
) или ложным отрицательным, если первый файл, расширенный из этого, является, например, символической ссылкой на несуществующий файл или файл в каталог, к которому у вас нет доступа (вы хотите добавить|| [ -L "$1" ]
).-e
совпадении 0 или 1. Это не работает для нескольких матчей, потому что это станет[ -e file1 file2 ]
и это не получится. Также см. Github.com/koalaman/shellcheck/wiki/SC2144 для обоснования и предлагаемых решений.Если у вас есть набор globfail, вы можете использовать этот сумасшедший (что вы действительно не должны)
или
источник
(shopt -s failglob; : *) 2>/dev/null && echo exists
test -e имеет неудачное предупреждение о том, что битые символические ссылки не существуют. Так что вы можете проверить это тоже.
источник
-o
и-a
вtest
/[
. Например, здесь, он терпит неудачу , если$1
это=
в большинстве реализаций. Используйте[ -e "$1" ] || [ -L "$1" ]
вместо этого.Чтобы несколько упростить ответ MYYN, основываясь на его идее:
источник
[a]
, есть файл с именем[a]
, но нет файла с именемa
? Мне все еще нравитсяnullglob
за это. Кто-то может расценить это как педантичный, но мы можем быть настолько же правы, насколько это разумно.[a]
должен совпадать толькоa
с буквальным именем файла[a]
.Исходя из ответа flabdablet , для меня кажется, что самым простым (не обязательно самым быстрым) будет просто использовать find , оставляя расширение glob на shell, например:
Или
if
как:источник
find
ответ flabdablet, потому что он принимает пути в глобусе, и это более кратко (не требует и-maxdepth
т.д.). Это также кажется лучше, чем егоstat
ответ, потому что он не продолжает делать дополненияstat
при каждом дополнительном глобальном совпадении. Я был бы признателен, если бы кто-нибудь мог внести угловой случай, когда это не работает.-maxdepth 0
потому что это обеспечивает большую гибкость при добавлении условий. например, предположим, что я хочу ограничить результат только соответствующими файлами. Я мог бы попытатьсяfind $glob -type f -quit
, но это возвратило бы true, если глобус НЕ соответствовал файлу, но действительно совпадал с каталогом, который содержал файл (даже рекурсивно). Напротивfind $glob -maxdepth 0 -type f -quit
, вернул бы true, только если сам шарик соответствовал хотя бы одному файлу. Обратите внимание, чтоmaxdepth
это не мешает глобу иметь компонент каталога. (К вашему сведению2>
достаточно. Не нужно&>
)find
в первую очередь состоит в том, чтобы избежать генерации оболочкой и сортировки потенциально огромного списка совпадений глобуса;find -name ... -quit
будет соответствовать не более одного имени файла. Если сценарий полагается на передачу сгенерированного оболочкой списка совпадений globfind
, вызов которого приводит только кfind
ненужным накладным расходам при запуске процесса. Простое тестирование полученного списка непосредственно на предмет пустоты будет быстрее и понятнее.У меня есть еще одно решение:
Это хорошо работает для меня. Есть ли какие-то угловые случаи, по которым я скучаю?
источник
В Bash вы можете использовать массив; если глобус не совпадает, ваш массив будет содержать одну запись, которая не соответствует существующему файлу:
Примечание: если вы
nullglob
установили,scripts
будет пустой массив, и вы должны проверить с[ "${scripts[*]}" ]
или[ "${#scripts[*]}" != 0 ]
вместо. Если вы пишете библиотеку, которая должна работать с или безnullglob
, вы захотитеПреимущество этого подхода заключается в том, что у вас есть список файлов, с которыми вы хотите работать, вместо того, чтобы повторять операцию glob.
источник
if [ -e "${scripts[0]}" ]...
? Вы также допускаете возможность установки набора опций оболочки ?nounset
что активен. Кроме того, может быть (немного) дешевле проверить, что строка не пуста, чем проверить наличие файла. Хотя вряд ли, учитывая, что мы только что выполнили глоб, означает, что содержимое каталога должно быть свежим в кеше ОС.Эта мерзость, кажется, работает:
Это, вероятно, требует bash, а не sh.
Это работает, потому что опция nullglob заставляет глобус вычислять пустую строку, если совпадений нет. Таким образом, любой непустой вывод команды echo указывает, что глобус соответствует чему-либо.
источник
if [ "`echo *py`" != "*py"]
*py
.py
,`echo *py`
будет оцениваться*py
.*py
, что является неправильным результатом.*py
подходящего файла , ваш скрипт будет отображать "Glob matched"?Я не видел этот ответ, поэтому я решил поставить его там:
источник
объяснение
Если нет совпадений для
glob*
, то$1
будет содержать'glob*'
. Тест-f "$1"
не будет верным, потому чтоglob*
файл не существует.Почему это лучше, чем альтернативы
Это работает с sh и производными: ksh и bash. Он не создает никаких вложенных оболочек.
$(..)
и`...`
команды создают вложенную оболочку; они разворачивают процесс и поэтому работают медленнее, чем это решение.источник
Как это в удар(тестовые файлы, содержащие
pattern
):Это гораздо лучше, чем
compgen -G
: потому что мы можем различать больше случаев и более точно.Может работать только с одним символом подстановки
*
источник
Обратите внимание, что это может занять очень много времени, если есть много совпадений или медленный доступ к файлам.
источник
[a]
используется, когда файл[a]
присутствует, а файлa
отсутствует. Он скажет «найдено», хотя единственный файл, которому он должен соответствоватьa
, на самом деле отсутствует.источник
nullglob
опцию shell.nullglob
это клуджем. Сравнение одного результата с исходным шаблоном - это клочок (и склонность к ложным результатам), использованиеnullglob
- нет.nullglob
клудж.источник
glob*
и, например, у вас нет записи для перечисления этих каталогов.ls | grep -q "glob.*"
Не самое эффективное решение (если в каталоге много файлов, оно может быть медленным), но оно простое, легко читаемое и имеет то преимущество, что регулярные выражения являются более мощными, чем простые шаблоны bash glob.
источник
источник