Как я могу программно определить, соответствует ли имя файла шаблону оболочки?

Я хотел бы сказать, будет ли строка $string соответствовать шаблону $pattern glob $pattern . $string может быть или не быть именем существующего файла. Как я могу это сделать?

Предположим, что для входных строк следующие форматы:

 string="/foo/bar" pattern1="/foo/*" pattern2="/foo/{bar,baz}" 

Я хотел бы найти bash-идиому, которая определяет, будет ли $string соответствовать $pattern2 , $pattern2 или любому другому произвольному шаблону glob. Вот что я пробовал до сих пор:

  1. [[ "$string" = $pattern ]]

    Это почти работает, за исключением того, что $pattern интерпретируется как шаблон строки, а не как шаблон глобуса.

  2. [ "$string" = $pattern ]

    Проблема с этим подходом заключается в том, что $pattern расширяется, а затем выполняется сравнение строк между $string и расширением $pattern .

  3. [[ "$(find $pattern -print0 -maxdepth 0 2>/dev/null)" =~ "$string" ]]

    Это работает, но только если $string содержит файл, который существует.

  4. [[ $string =~ $pattern ]]

    Это не работает, потому что оператор =~ заставляет $pattern интерпретироваться как расширенное регулярное выражение, а не шаблон glob или wildcard.

5 Solutions collect form web for “Как я могу программно определить, соответствует ли имя файла шаблону оболочки?”

Общее решение этой проблемы отсутствует. Причина в том, что в bash расширение расширений (т. {pattern1,pattern2,...} и расширение имени файла (aka glob patterns) считаются отдельными вещами и расширяются в разных условиях и в разное время. Вот полный список расширения, которые выполняет bash:

  • расширение скобы
  • расширение тильды
  • параметрическое и переменное расширение
  • замена команды
  • арифметическое расширение
  • расщепление слов
  • расширение пути

Поскольку мы заботимся только о подмножестве этих (возможно, скобках, тильде и расширении пути), можно использовать определенные шаблоны и механизмы, чтобы ограничить расширение управляемым способом. Например:

 #!/bin/bash set -f string=/foo/bar for pattern in /foo/{*,foo*,bar*,**,**/*}; do [[ $string == $pattern ]] && echo "$pattern matches $string" done 

Запуск этого сценария генерирует следующий вывод:

 /foo/* matches /foo/bar /foo/bar* matches /foo/bar /foo/** matches /foo/bar 

Это работает, потому что set -f отключает расширение имени пути, поэтому в инструкции for pattern in /foo/{*,foo*,bar*,**,**/*} происходит только расширение расширений и расширение тильды. Затем мы можем использовать тестовую операцию [[ $string == $pattern ]] для проверки расширения пути после того, как расширение скобки уже выполнено.

Как заметил Патрик, вам нужен «другой тип» рисунка:

 [[ /foo/bar == /foo/@(bar|baz) ]] string="/foo/bar" pattern="/foo/@(bar|baz)" [[ $string == $pattern ]] 

Котировки там не нужны.

Я не верю, что {bar,baz} это шаблон оболочки оболочки (хотя, конечно, /foo/ba[rz] ), но если вы хотите узнать, соответствует ли $string $pattern :

 case "$string" in ($pattern) put your successful execution statement here;; (*) this is where your failure case should be ;; esac 

Вы можете делать столько, сколько хотите:

 case "$string" in ($pattern1) do something;; ($pattern2) do differently;; (*) still no match;; esac 

Я бы использовал grep:

 #!/bin/bash string="/foo/bar" pattern1="/foo/*" pattern2="/foo/{bar,baz}" if echo $string | grep -e "$pattern1" > /dev/null; then echo $string matches $pattern1 fi if echo $string | grep -e "$pattern2" > /dev/null; then echo $string matches $pattern2 fi 

Что дает результат:

 ./test2.bsh /foo/bar matches /foo/* 

в zsh:

 [[ $string = $~pattern ]] && print true 
  • Как скопировать все файлы HTML из дерева каталогов в один каталог
  • Работа rm / ls с
  • Как удалить все символические ссылки со специальной целью?
  • bash regex: звездочка дает неоднозначные результаты поиска с помощью grep
  • Как скопировать файл в домашний каталог каждого пользователя в BASH?
  • Какова настройка в bash для globbing, чтобы контролировать, совпадает ли * с точечными файлами
  • как фильтровать по звездочке или аналогичному выражению rsync в zsh
  • Согласование только числовых расширений файлов
  • Что делает `mv ./*` без указания адресата?
  • Выбор файлов, начинающихся с $ LETTER, или буквы позже, чем $ LETTER в алфавите
  • Почему mv удалил файл с mv id_rsa * .old?
  • Interesting Posts

    Как сделать минимальный загрузочный linux (только с терминалом) из исходного кода ядра?

    BashScript работает от терминала, но не от CronTab

    Выполнять CGI-скрипты на пользовательской плате OMAP4 как root

    Низкий уровень громкости на материнской плате Z97 и Linux Mint KDE

    pssh (Parallel-ssh), передающий разные параметры для каждого хоста

    политика apt-cache gimp libgegl-0.2-0

    «Имя файла должно быть абсолютным путем или списком блокировок» Ошибка при загрузке

    Как получить доступ к машине за ограниченным шлюзом NAT я не умею?

    Проблемы при попытке выполнить sh-файл из другого sh-файла

    Как добавить строку, начинающуюся с STDIN с отметкой времени в эпоху?

    Как определить путь ffmpeg при компиляции другого программного обеспечения?

    локализация справочных страниц в Linux (Ubuntu)

    В чем основные отличия между BSD и GNU / Linux?

    Как сделать значения столбца разделенным запятой?

    Как заменить «& # x5c» на «/» в файле с помощью командной строки?

    Linux и Unix - лучшая ОС в мире.