использовать регулярное выражение в условии if в bash

88

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

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

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

Тим
источник

Ответы:

129

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

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

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

if [[ $gg =~ ^....grid.*$ ]] ; then echo $gg; fi
Приостановлено до дальнейшего уведомления.
источник
Итак, есть два способа сопоставления строк: шаблон глобуса и регулярное выражение? Glob pettern используется не только для имен файлов? В bash, когда использовать шаблон глобуса, а когда использовать регулярное выражение? Благодарность!
Тим
1
@Tim: Globbing доступен в большинстве или во всех версиях Bash. Сопоставление регулярных выражений доступно только в версии 3 и новее, но я бы рекомендовал использовать его только в версии 3.2 и новее. Регулярные выражения гораздо более универсальны, чем глобусы.
Приостановлено до дальнейшего уведомления.
14
if [[ $gg =~ ^....grid.* ]]
Игнасио Васкес-Абрамс
источник
1
Вы должны иметь возможность использовать ". {4}" вместо "....", т.е. "^. {4} grid. *". Его легче читать и понимать.
user276648 01
8

Добавление этого решения с grepбазовыми 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(тихий) в качестве альтернативы перенаправлению на /dev/null, но перенаправление снова является наиболее переносимым.

владр
источник
забыл закрытие ")" для egrep
ghostdog74
5
Используйте grep -qвместо grep >/dev/null.
bfontaine
3

@OP,

Glob pettern используется не только для имен файлов?

Нет, шаблон "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

В bash, когда использовать шаблон глобуса, а когда использовать регулярное выражение? Благодарность!

Регулярные выражения более универсальны и «удобны», чем «глобальные шаблоны», однако, если вы не выполняете сложные задачи, которые «глобальное / расширенное глобальное выражение» не может обеспечить легко, тогда нет необходимости использовать регулярное выражение. Регулярные выражения не поддерживаются для версии bash <3.2 (как упоминал Деннис), но вы все равно можете использовать расширенную глобализацию (путем настройки extglob). для расширенного подстановки см. здесь и несколько простых примеров здесь .

Обновление для OP: пример поиска файлов, которые начинаются с 2 символов (точки "." Означает 1 символ), за которыми следует "g" с использованием регулярного выражения

например, вывод

$ shopt -s dotglob
$ ls -1 *
abg
degree
..g

$ for file in *; do [[ $file =~ "..g" ]] && echo $file ; done
abg
degree
..g

В приведенном выше примере файлы совпадают, потому что их имена содержат 2 символа, за которыми следует «g». (т.е. ..g).

Эквивалент с подстановкой будет примерно таким: (см. В справочнике значение ?и *)

$ for file in ??g*; do echo $file; done
abg
degree
..g
призрачная собака74
источник
Спасибо ghostdog74. Можно ли в Bash версии выше 3.2 использовать регулярное выражение для замены шаблона glob везде, где последний появляется? Или регулярное выражение можно использовать только в особых обстоятельствах? Например, я обнаружил, что ls ?? g работает, а ls ..g - нет.
Тим
Вам не помешает использовать регулярное выражение, если в этом есть необходимость. Тебе решать. Обратите внимание: синтаксис регулярного выражения отличается от синтаксиса подстановки оболочки. так ls ..gне работает. Вы говорите оболочке искать файл с именем ..g. Что же касается изучения синтаксиса регулярных выражений, вы можете попробовать perldoc perlretut, perldoc perlrequickили сделать info sedв командной строке.
ghostdog74