Используйте регулярное выражение в if-состоянии в bash
Интересно, как правило использовать регулярное выражение в условии if в bash?
Вот пример
$ gg=svm-grid-ch
$ if [[ $gg == *grid* ]] ; then echo $gg; fi
svm-grid-ch
$ if [[ $gg == ^....grid* ]] ; then echo $gg; fi
$ if [[ $gg == ....grid* ]] ; then echo $gg; fi
$ if [[ $gg == s...grid* ]] ; then echo $gg; fi
$
Почему последние три не совпадают?
Надеюсь, вы могли бы дать как можно больше общих правил, а не только для этого примера.
Ответы
Ответ 1
При использовании шаблона glob знак вопроса представляет собой один символ, а звездочка представляет последовательность из нуля или более символов:
if [[ $gg == ????grid* ]] ; then echo $gg; fi
При использовании регулярного выражения точка представляет собой одиночный символ, а звездочка представляет собой ноль или более предыдущего символа. Таким образом, ".*
" представляет ноль или более любого символа, "a*
" представляет собой ноль или более "a", "[0-9]*
" представляет собой ноль или более цифр. Другим полезным (среди многих) является знак плюса, который представляет один или несколько предшествующих символов. Таким образом, "[a-z]+
" представляет один или несколько букв в нижнем регистре (в локали C - и некоторые другие).
if [[ $gg =~ ^....grid.*$ ]] ; then echo $gg; fi
Ответ 2
Использование = ~
для проверки регулярного выражения Учебное пособие по регулярным выражениям
Ответ 3
if [[ $gg =~ ^....grid.* ]]
Ответ 4
Добавление этого решения с помощью встроенных функций grep
и basic sh
для тех, кто заинтересован в более портативном решении (независимо от версии bash
, также работает с обычным старым sh
, на платформах, отличных от Linux).
# GLOB matching
gg=svm-grid-ch
case "$gg" in
*grid*) echo $gg ;;
esac
# REGEXP
if echo "$gg" | grep '^....grid*' >/dev/null ; then echo $gg ; fi
if echo "$gg" | grep '....grid*' >/dev/null ; then echo $gg ; fi
if echo "$gg" | grep 's...grid*' >/dev/null ; then echo $gg ; fi
# Extended REGEXP
if echo "$gg" | egrep '(^....grid*|....grid*|s...grid*)' >/dev/null ; then
echo $gg
fi
Некоторые воплощения grep
также поддерживают параметр -q
(quiet) как альтернативу перенаправлению на /dev/null
, но перенаправление снова является наиболее переносимым.
Ответ 5
@OP,
Is glob pettern not only used for file names?
Нет, шаблон "glob" используется не только для имен файлов. вы используете его для сравнения строк. В ваших примерах вы можете использовать case/esac для поиска шаблонов строк.
gg=svm-grid-ch
# looking for the word "grid" in the string $gg
case "$gg" in
*grid* ) echo "found";;
esac
# [[ $gg =~ ^....grid* ]]
case "$gg" in ????grid*) echo "found";; esac
# [[ $gg =~ s...grid* ]]
case "$gg" in s???grid*) echo "found";; esac
In bash, when to use glob pattern and when to use regular expression? Thanks!
Regex более универсальны и "удобны", чем "шаблоны глобуса", однако, если вы не выполняете сложные задачи, которые невозможно выполнить с помощью "globbing/extended globbing", тогда нет необходимости использовать регулярное выражение.
Regex не поддерживаются для версии bash < 3.2 (как упоминалось Денисом), но вы все равно можете использовать расширенное globbing (путем установки extglob
). для расширенного globbing, см. здесь и некоторые простые примеры здесь.
Обновление для OP: пример поиска файлов, начинающихся с двух символов (точки "." означает 1 char), а затем "g" с использованием regex
например, вывод
$ shopt -s dotglob
$ ls -1 *
abg
degree
..g
$ for file in *; do [[ $file =~ "..g" ]] && echo $file ; done
abg
degree
..g
В приведенном выше примере файлы сопоставляются, поскольку их имена содержат 2 символа, за которыми следует "g". (т.е. ..g
).
Эквивалент с globbing будет примерно таким: (смотрите ссылка для значения ?
и *
)
$ for file in ??g*; do echo $file; done
abg
degree
..g