Почему $ anchor в конце строки не работает с командой grep, хотя якорь в начале строки ^?

19

Очень плохо знаком с UNIX, но не новичок в программировании. Использование терминала на MacBook. В целях управления и поиска списков слов для построения кроссвордов, я пытаюсь разобраться с командой Grep и ее вариациями. Кажется довольно простым, но рано зацикливаться на том, что, как я думал, должно быть простым делом.

Когда я вхожу

grep "^COW" masternospaces.txt

Я получаю то, что хочу: список всех слов, начинающихся с COW.

Но когда я вхожу

grep "COW$" masternospaces.txt

Я ожидаю получить список слов, оканчивающихся на COW (таких слов много), и ничего не возвращается вообще.

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

Есть идеи, что здесь может происходить?

DTalvacchio
источник
3
Каково происхождение файла masternospaces.txt? возможно ли, что он имеет линейные окончания в стиле Windows (CR-LF) вместо LF в стиле Unix?
SteelDriver
2
Не уверен, но вы ищете список слов или список строк ... ?
mikeserv
Steeldriver-- Нечто подобное было моей первой мыслью. Не был уверен, как проверить, что там происходит, или каковы были возможности. Предполагается, что конечный возврат был конечным. Этот файл представляет собой массивный сборник из нескольких источников. Я даже не уверен, какой из них будет считаться оригинальным файлом. И это было по крайней мере три текстовых процессора на компьютерах ПК и Mac. Что может быть лучшим способом увидеть, какие терминации он использует?
DTalvacchio
mikeserv-- В этом файле .txt каждая строка - это просто слово (или фраза без пробелов между словами, поэтому снова слово). Так что я ищу строки, наверное. , , просто в каждой строке есть только одно из того, что я рассматриваю как слово для целей кроссворда.
DTalvacchio
1
Вы можете использовать, hexdumpчтобы точно проверить, как отформатированы окончания строк. Я предлагаю вам использовать мой любимый формат: hexdump -e '"%08_ad (0x%08_ax) "8/1 "%02x "" "8/1 "%02x "' -e '" "8/1 "%_p""|"8/1 "%_p""\n"' masternospaces.txt. Получив выходные данные, проверьте окончания строк: 0a-> LF, 0d-> CR.
user43791

Ответы:

23

Как упомянул @steeldriver, проблема, вероятно, вызвана тем, что стиль окончания строки отличается от grepожидаемого.

Чтобы проверить окончания строки

Вы можете использовать, hexdumpчтобы точно проверить, как отформатированы окончания строк. Я предлагаю вам использовать мой любимый формат:

hexdump -e '"%08_ad (0x%08_ax)    "8/1 "%02x ""   "8/1 "%02x "' -e '"    "8/1 "%_p""|"8/1 "%_p""\n"' masternospaces.txt

Получив выходные данные, проверьте окончания строк: 0a-> LF, 0d-> CR. Очень быстрый пример даст что-то вроде этого:

$ hexdump -e '"%08_ad (0x%08_ax)    "8/1 "%02x ""   "8/1 "%02x "' -e '"    "8/1 "%_p""|"8/1 "%_p""\n"' masternospaces.txt
00000000 (0x00000000)    4e 6f 20 43 4f 57 20 65   6e 64 69 6e 67 0d 0a 45    No COW e|nding..E
00000016 (0x00000010)    6e 64 69 6e 67 20 69 6e   20 43 4f 57 0d 0a          nding in| COW..

Обратите внимание на концы строк в формате DOS: 0d 0a.

Чтобы изменить окончания строки

Вы можете увидеть здесь или здесь различные способы изменения конца строки с использованием различных инструментов, но для разовой работы вы всегда можете использовать vi / vim:

vim masternospaces.txt
:set fileformat=unix
:wq

Grep, ничего не меняя

Если вы просто хотите grepсоответствовать независимо от окончания строки, вы всегда можете указать окончание строки следующим образом:

grep 'COW[[:cntrl:]]*$' masternospaces.txt

Если отображается пустая строка, вы можете проверить, что вы действительно что-то сопоставили, используя -vпараметр cat:

grep 'COW[[:cntrl:]]*$' masternospaces.txt | cat -v

Мой личный фаворит

Вы также можете как grep, так и стандартизировать вывод, используя sed:

sed -n '/COW^M*$/{;s/^M//g;p;};' masternospaces.txt

где ^Mполучается, набрав Ctrl-V Ctrl-Mна клавиатуре.

Надеюсь это поможет!

user43791
источник
Это все очень полезно. У меня сегодня нет времени, но завтра я внимательно изучу все это и выясню, что к чему. Если в то же время у кого-то из вас есть ссылка на ваше любимое справочное руководство по командам Unix, чтобы я мог немного научиться тому, как все работает, я был бы признателен. Я собирал кусочки здесь и там, но мне еще не удалось найти один источник, который мне нужен для объяснений. Спасибо всем и проверю завтра с надеждой успешного обновления. --D
DTalvacchio
Жаль, что у этого поста нет закрытия, по крайней мере для меня. Я не могу понять, как мне соответствовать концу строки. Если я сделаю шестнадцатеричный дамп, я не смогу найти красивую линию, заканчивающуюся как ваш пример выше. Я не знаком с работой с шестнадцатеричным кодом, поэтому, возможно, я не правильно читаю. Я также попробовал предложенный [[:cntrl:]]@ user43791, но он мне ничего не подходит. Это не имеет никакого смысла. Я использую GNU grep 2.20 и анализирую вывод из nDPI, который был записан в текстовый файл
harperville
@harperville Если ты cat -v yourfile.ext, что ты видишь?
user43791
Ну, ничего интересного или неожиданного. Просто содержимое, как я ожидаю увидеть их. Что-то конкретное, что вы ищете? Я не могу вставить вывод здесь, но я просто вижу содержимое. Обычный ол "ASCII английский текст" согласно file.
Harperville
@harperville Никаких лишних "^ M" в конце каждой строки? Не могли бы вы вставить первые несколько строк гексагона?
user43791
1

Хотя вы можете использовать «стандартный» синтаксис RegEx с grep (как в ответе @ user43791 ), grep также имеет другие идентификаторы для обозначения входных границ.

Совпадения для начала и конца всей строки \`(обратный удар) (вместо ^) и \'(апостроф) (вместо $).

Так что для вашей исходной команды вы должны использовать: grep "COW\'" masternospaces.txt

Дополнительное примечание: также важно отметить, что ?и +будет рассматриваться буквально, если вы не избежите их использования \?и не \+сделаете их аналогами селектора в стиле RegEx.

Источник: grepсинтаксис регулярного выражения

samthecodingman
источник
grep принимает ^ (каретку) для начала и \ '(апостроф) для конца
GypsyCosmonaut
1

Еще один способ удалить \rперед grep:

... | dos2unix | egrep 'COW$' | ...

Мне нравится, что это очень ясно, потому что я не помню такие вещи, как [[:cntrl:]]долго.

Хавьер
источник
-2

«COW $», когда bash установил параметр для grep, он интерпретировался как «COW», где обрабатывает «$» как «», поскольку $ является символом escape. когда $ не соответствует никому, это интерпретируется bash-оболочкой как пустая строка, поэтому вы должны использовать grep 'COW $' masternospaces.txt.

Янян
источник
3
поскольку нет действительного расширения $, оно будет оставлено bash и использовано grep. Убедитесь сами: echo "COW$"- $все еще будет там.
Джефф Шаллер
-3

В BSD grep вам нужно экранировать "$" и заключать вашу строку в двойные кавычки:

"COW\$"
user297403
источник
1
Хм ... нет. Это $не будет особенным для оболочки, потому что содержимое после него не является допустимым именем переменной оболочки. Использование одинарных кавычек вокруг статических строк - лучшая идея, но здесь не будет никакой разницы.
Кусалананда