Почему [az] звездочка соответствует номерам?


13

У меня есть 3 каталога на текущий путь.

$ls
a_0db_data  a_clean_0db_data  a_clean_data
$ls a_*_data
a_0db_data:

a_clean_0db_data:

a_clean_data:

$ls a_[a-z]*_data
a_clean_0db_data:

a_clean_data:

Я ожидал, что последняя команда ls будет соответствовать только a_clean_data. Почему это также соответствует тому, который содержит 0?

bash --version
GNU bash, version 4.2.24(1)-release (i686-pc-linux-gnu)

2
Посмотрите этот вопрос, чтобы узнать больше о разнице между регулярным выражением и глобусом.
Тердон

4
То, что a_*_dataсовпадение с любым из этих файлов вас не удивило?
Ктулху

@Cthulhu ты меня понял!
user13107

Ответы:


29

[a-z]Часть не то , что совпадает с номером; это *. Вы можете быть запутанной оболочка подстановки и регулярные выражения .

Такие инструменты, как grepпринимают различные разновидности регулярных выражений ( базовые по умолчанию, -Eрасширенные, -Pдля регулярных выражений Perl )

Например, ( -vинвертирует совпадение)

$ ls a_[a-z]*_data | grep -v "[0-9]"
a_clean_data

Если вы хотите использовать регулярное выражение bash, вот пример того, как проверить, является ли переменная $refцелым числом:

re='^[0-9]+$'
if ! [[ $ref =~ $re ]] ; then
  echo "error"
fi

Как использовать Bash Regex тогда? (см. tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_01.html )
user13107


21

Итак, проблема в том, почему a_[a-z]*_dataсовпадает a_clean_0db_data?

Это можно разбить на четыре части:

  • a_соответствует началу a_clean_0db_data, оставляя clean_0db_dataдля сопоставления

  • [a-z]соответствует любому символу в диапазоне a-z(например c), оставляя lean_0db_dataдля сравнения

  • * соответствует любому количеству символов, например lean_0db

  • _data соответствует висячему _data

В регулярных выражениях [a-z]*будет означать любое количество символов (включая ноль) в диапазоне a..z , но вы имеете дело с глобализацией оболочки, а не с регулярными выражениями.

Если вам нужны регулярные выражения, у нескольких findреализаций есть -regexпредикат для этого:

find . -maxdepth 1 -regex "^.*/a_[a-z]*_data$"

-maxdepthТолько здесь , чтобы ограничить поиск-результаты в папку находятся. Регулярное выражение соответствует всему файлу, поэтому я добавил , ^.*/чтобы соответствовать путям-части


11

*в шаблонах оболочки соответствует 0 или более символов. Это не должно быть перепутано с *оператором регулярного выражения, который означает 0 или больше предшествующего атома .

В *базовых шаблонах оболочки нет эквивалента регулярному выражению . Тем не менее, различные оболочки имеют расширения для этого.

  • kshимеет *(something):

    ls a_*([a-z])_data
  • Вы можете иметь то же самое bashс shopt -s extglobили zshс setopt kshglob:

    shopt -s extglob
    ls a_*([a-z])_data
  • В zshс extendedglobвключен, #эквивалентно регулярному выражению *:

    setopt extendedglob
    ls a_[a-z]#_data
  • В последних версиях ksh93вы также можете использовать регулярные выражения в глобах. Вот с расширенными регулярными выражениями:

    ls ~(E:a_[a-z]*_data)

Обратите внимание, что это [a-z]соответствует разным вещам в зависимости от текущей локали. Как правило , он соответствует только 26 aна zлатинские , не акцентированные буквы в Cлокали. В других регионах оно обычно соответствует большему количеству и не всегда имеет смысл. Чтобы соответствовать букве в вашем регионе, вы можете предпочесть [[:alpha:]].


Не могли бы вы привести пример [a-z]сопоставления больше, чем 26 букв в языке C? Что я помню, когда в последний раз смотрел на это, все кодировки, практически используемые в вариантах Unix, имели ISO-646 в качестве основы (тогда верхние 128 кодов использовались по-разному, непосредственно для символов в кодировках, таких как ISO-8859-X, объединенных в кодировки, такие как UTF-8 или семейство EUC). Даже в AIX не было локалей EBCDIC (по крайней мере, так, как мне доступно). Я помню, как пытался выяснить, требовали ли этого стандарты POSIX / UNIX, но я не помню результат.
AProgrammer

1
@AProgrammer, это не зависит от кодировки, это основано на порядке сортировки (LC_COLLATE). [a-z]обычно включает éили í(но не обязательно ź) в локали, где есть кодировка, независимо от того, находится ли кодовая точка в этой кодировке между a и z или нет. Только язык C гарантирует порядок сортировки на основе значения кодовой точки. Смотрите этот другой ответ для более подробной информации.
Стефан Шазелас

Хорошо, что я пропустил, так это то, что диапазон интерпретировался в соответствии с текущей последовательностью сопоставления.
AProgrammer
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.