Grep с диапазоном символов регулярного выражения, который включает символ NULL

Когда я включаю символ NULL (\x00) в диапазон символов регулярного выражения в BSD grep, результат оказывается неожиданным: нет совпадений символов. Почему это происходит?

Вот пример:

$ echo 'ABCabc<>/ă' | grep -o [$'\x00'-$'\x7f']

Здесь я ожидаю, что все символы до последнего будут совпадать, однако результат не выводится (нет совпадений).

В качестве альтернативы, когда я начинаю диапазон символов с \x01, он работает так, как ожидалось:

$ echo 'ABCabc<>/ă' | grep -o [$'\x01'-$'\x7f']
A
B
C
a
b
c
<
>
/

Кроме того, вот мои версии grep и BASH:

$ grep --version
grep (BSD grep) 2.5.1-FreeBSD

$ echo $BASH_VERSION
3.2.57(1)-release

person Lucas Leblow    schedule 01.03.2021    source источник


Ответы (2)


Отметив, что $'...' является конструкцией кавычек оболочки, ,

$ echo 'ABCabc<>/ă' | grep -o [$'\x00'-$'\x7f']

попытается передать буквальный символ NUL как часть аргумента командной строки в grep. Это невозможно сделать в любой Unix-подобной системе, поскольку аргументы командной строки передаются процессу в виде строк с нулевым завершением. Таким образом, grep видит только аргументы -o и [.

Вам нужно будет создать некоторый шаблон, который соответствует байту NUL, не включая его буквально. Но я не думаю, что grep поддерживает экранирование \000 или \x00. Однако Perl это делает, поэтому он печатает строку ввода с NUL:

$ printf 'foo\nbar\0\n' |perl -ne 'print if /\000/'
bar

Кроме того, по крайней мере, GNU grep, похоже, не нравится такое выражение диапазона, поэтому, если бы вы использовали это, вы должны были бы сделать что-то другое. В локали C [[:cntrl:][:print:]]', возможно, может соответствовать символам от \x01 до \x7f, но я не проверял всесторонне. руководство по grep содержит некоторые описания классов.


Также обратите внимание, что [$'\x00'-$'\x7f'] имеет пару [ и ] без кавычек, а значит, является шаблоном оболочки. Это не связано с байтом NUL, но если у вас есть файлы, соответствующие глобусу (любые однобуквенные имена, если глобус работает в вашей системе — он не работает в моем Linux), или если были установлены failglob или nullglob , это, вероятно, даст нежелательные результаты. Вместо этого также укажите скобки: $'[\x00-\x7f]'.

person ilkkachu    schedule 01.03.2021
comment
grep ['a'-'b'] и grep '[a-b]' тоже одинаковые? - person oguz ismail; 02.03.2021
comment
@oguzismail, кроме первого шара, не так ли? - person ilkkachu; 02.03.2021
comment
То, что первый - это шар, не является незначительной разницей. Они не одинаковы. - person oguz ismail; 02.03.2021
comment
@oguzismail, для целей этого выпуска это незначительная разница. - person ilkkachu; 02.03.2021
comment
Вводит в заблуждение в любом случае. ['a'-'b'] может расшириться до пустой строки (nullglob), a, b, как a, так и b, или [a-b], или может привести к сбою команды (failglob), тогда как '[a-b]' всегда будет [a-b]. - person oguz ismail; 02.03.2021
comment
@oguzismail, да, на самом деле вы правы в том, что глобус в вопросе будет соответствовать любому однобуквенному имени, если оно вообще работает. Я намеренно игнорирую failglob, nullglob и возможность совпадения странных имен файлов, чтобы не уходить от темы, но однобуквенные имена файлов являются более вероятной проблемой. Назовите это ленью, если хотите, но отказ от ответственности обо всех причудах языка оболочки, к сожалению, довольно длинный, чтобы включать его в каждый пост... - person ilkkachu; 02.03.2021

В BSD grep вы можете использовать это:

LC_ALL=C grep -o '[[:print:][:cntrl:]]' <<< 'ABCabc<>/ă'

A
B
C
a
b
c
<
>
/

Или вы можете просто установить gnu grep с помощью пакета home brew и запустить:

grep -oP '[[:ascii:]]' <<< 'ABCabc<>/ă'
person anubhava    schedule 01.03.2021