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

Я хотел бы сказать, будет ли строка $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 
  • Выбор файлов, начинающихся с $ LETTER, или буквы позже, чем $ LETTER в алфавите
  • Почему `find -name * .jks` не возвращает некоторые файлы?
  • Расширение Shell glob после замены переменной цикла
  • Что означает знак вопроса в соответствующем шаблоне имени файла?
  • ffmpeg -pattern_type glob - не загружать файлы в правильном порядке
  • Как найти файлы с определенными расширениями, исключая только имена в текущем каталоге?
  • Как получить последние N файлов в каталоге?
  • Работа rm / ls с
  • Как я могу использовать '*' для захвата всего с исключениями
  • Цикл forach для вывода ls
  • Список только обычных файлов (но не каталогов) в текущем каталоге
  • Linux и Unix - лучшая ОС в мире.