Проблемы с регулярными выражениями в Bash: [^ negate] не работает


8

Когда я выполняю ls /directory | grep '[^term]'в Bash, я получаю регулярный список, как будто grepкоманда как-то игнорируется. Я пробовал то же самое с egrep, я пытался использовать это с двойными и одинарными кавычками, но без лучшего результата. Когда я пытаюсь, ls /directory | grep '^[term]я получаю все записи, начинающиеся с термина - как и ожидалось.

Я опробовал эту команду в онлайн-редакторе, где я могу протестировать свое регулярное выражение, и оно сработало как надо. Но не в Баш. Так что это работает в симуляции, но не в реальной жизни.

Я работаю над Crunchbang Linux 10. Надеюсь, этого достаточно, и я с нетерпением жду каждого намека, потому что неудача в выполнении на таком базовом уровне и потеря времени - это очень печально!


Я запутался из-за отрицания в названии. Хотите grepстроки, начинающиеся с термина. Или вы хотите использовать grep для строк, не содержащих термин вообще?
Бернхард

@ Бернхард: я хочу список без термина в квадратных скобках. Это не обязательно должен быть термин «срок»! Насколько я понял, [^ abc] означает, что ничего, содержащего a, b или c или любую их комбинацию, не должно быть в списке.
2013 года

Ответы:


12

Вы уверены, что то, что вы хотите, происходит? Когда вы бежите, ls /directory | grep '[^term]'вы, по сути, говорите не о буквах ter m. Это означает, что если файл имеет другие буквы в имени, он все равно будет отображаться в выходных данных ls. Возьмите следующий каталог, например:

$ ls
alpha  brave  bravo  charlie  delta

Теперь, если я бегу, ls |grep '^[brav]'я получаю следующее:

$ ls |grep '^[brav]'
alpha
brave
bravo

Как вы можете видеть, не только я , braveи bravoя тоже получил , alphaпотому что класс персонажа []будет получить любую букву из этого списка.

Следовательно, если я запущу, ls |grep '[^brav]'я получу все файлы, которые не содержат символов brav нигде в имени.

$ ls |grep '[^brav]'
alpha
bravo
brave
charlie
delta

Если вы заметили, что он включал полный список каталогов, потому что все файлы имели хотя бы одну букву, которая не была включена в класс символов.

Поэтому, как сказал Канвуанза, для обратного выражения «термин» вместо символов t e r mнеобходимо использовать это grep -v.

Например:

$ ls |grep -v 'brav'
alpha
charlie
delta

Также, если вы не хотите использовать файлы, которые имеют какие-либо символы в классе grep -v '[term]'. Это предотвратит появление файлов, в которых есть любой из этих символов. (Ответ Канвуанзы)

Например:

$ ls |grep -v '[brav]'

Как вы можете видеть, в списке не было файлов, потому что все файлы в этом каталоге содержали хотя бы одну букву из этого класса.

Приложение:

Я хотел добавить, что с помощью PCRE можно использовать просто регулярное выражение для фильтрации с использованием выражений отрицания. Для этого нужно использовать что - то известное как негативный взгляд вперед регулярное выражение: (?!<regex>).

Таким образом, используя приведенный выше пример, вы можете сделать что-то подобное, чтобы получить желаемые результаты без использования grepфлагов.

$ ls | grep -P '^(?!brav)'
alpha
charlie
delta

Чтобы деконструировать это регулярное выражение, оно сначала сопоставляется в начале строки, ^а затем ищет строки, которые не соответствуют bravпоследующим. Только alpha, charlieи deltaматч так что те являются единственными, которые печатаются.


1
Это означает, что если у файла есть другие буквы в имени, он все равно будет отображаться в выводе ls. Это отвечает на довольно много вопросов! :) Таким образом, лучший способ на данный момент, кажется, -vвариант. Спасибо за вашу поддержку! Этот вопрос действительно испортил мой день, когда твой ответ осветил мой вечер!
erch

+1 за negative look-ahead regex.
Абхишек Кашьяп

3

Я думаю, этот grep -vфлаг делает то, что вы хотите. Со страницы руководства :

-v, --invert-match
    Invert the sense of matching, to select non-matching lines.

Вы можете использовать ls /directory | grep -v [term]для печати любых несоответствующих строк.


Мне известна эта опция, но я ошибаюсь, полагая, что [^ xyz] противоположен [xyz] и должен работать в любом случае? Я также хочу избегать редактирования каких-либо настроек в любом месте на таком базовом уровне. Использование опции инвертирования и / или редактирования настроек, безусловно, хороший способ, но, насколько я понял, это должно работать без из коробки.
2013 года

Я предполагаю, что вы правы, это общее обозначение для отрицания класса (т.е. ... [^abc]Но я почти уверен, что grep не поддерживает отрицания класса, кроме нескольких стандартных (например [[:^digits:]]). Поддержка отрицания в Grep ужасна !
Педро Ласерда

Grep поддержка отрицания ужасна! И это намеки, которые являются настоящей глазурью на торте. У меня те же проблемы с egrep, и я далёк от использования [по крайней мере для меня] более продвинутых команд в данный момент. Можете ли вы предложить команду, которая обеспечивает лучшие результаты и меньше головной боли?
erch

@ cellar.dweller, grepобработка классов символов просто прекрасна. Это просто означает нечто совершенно иное, чем то, что вы (неправильно) понимаете. [abc]означает один из a, bили c; [^abc]означает что-нибудь, кроме вышесказанного. Это один персонаж.
vonbrand

@ cellar.dweller: Я думаю, что вашей самой большой проблемой является неправильное понимание регулярных выражений, в частности классов персонажей внутри регулярных выражений.
Тинк
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.