Подтвердить что ты не робот

Используйте регулярное выражение в 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  
$   

Почему последние три не совпадают?

Надеюсь, вы могли бы дать как можно больше общих правил, а не только для этого примера.

4b9b3361

Ответ 1

При использовании шаблона glob знак вопроса представляет собой один символ, а звездочка представляет последовательность из нуля или более символов:

if [[ $gg == ????grid* ]] ; then echo $gg; fi

При использовании регулярного выражения точка представляет собой одиночный символ, а звездочка представляет собой ноль или более предыдущего символа. Таким образом, ".*" представляет ноль или более любого символа, "a*" представляет собой ноль или более "a", "[0-9]*" представляет собой ноль или более цифр. Другим полезным (среди многих) является знак плюса, который представляет один или несколько предшествующих символов. Таким образом, "[a-z]+" представляет один или несколько букв в нижнем регистре (в локали C - и некоторые другие).

if [[ $gg =~ ^....grid.*$ ]] ; then echo $gg; fi

Ответ 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