Dlaczego kotwica $ końca linii nie działa z poleceniem grep, mimo że kotwica ^ linii jest?

19

Bardzo nowy w systemie UNIX, ale nie nowy w programowaniu. Korzystanie z terminala na MacBooku. Do celów zarządzania listami słów i budowania krzyżówek próbuję się przydać z poleceniem Grep i jego odmianami. Wydaje się to dość proste, ale wcześnie się rozłączam z tym, co moim zdaniem powinno być prostym przypadkiem.

Kiedy wejdę

grep "^COW" masternospaces.txt

Dostaję to, czego chcę: listę wszystkich słów zaczynających się od COW.

Ale kiedy wejdę

grep "COW$" masternospaces.txt

Spodziewam się, że otrzymam listę słów kończących się na COW (jest wiele takich słów) i nic nie jest zwracane.

Plik jest zwykłym plikiem tekstowym, w którym każdy wiersz zawiera tylko słowo (lub frazę bez spacji) we wszystkich wielkich literach.

Masz pomysł, co się tutaj dzieje?

DTalvacchio
źródło
3
Jakie jest pochodzenie pliku masternospaces.txt? czy to możliwe, że ma końce linii w stylu Windows (CR-LF) zamiast LF w stylu Unix?
steeldriver
2
Nie jestem pewien, ale szukasz listy słów lub listy linii ... ?
mikeserv
steeldriver-- Coś takiego było moją pierwszą myślą. Nie byłem pewien, jak sprawdzić, co się tam dzieje, a nawet jakie były możliwości. Zakładając, że zwrot końcowy był zwrotem końcowym. Ten plik to ogromne kompendium z kilku źródeł. Nie jestem nawet pewien, który z nich byłby uważany za oryginalny plik. I to przez co najmniej trzy edytory tekstu na komputerach PC i Mac. Jaki może być najlepszy sposób, aby zobaczyć, jakiego rodzaju terminacji używa?
DTalvacchio
mikeserv-- W tym pliku .txt każda linia jest tylko słowem (lub frazą bez spacji między słowami, więc znowu „słowo”). Więc chyba szukam linii. . . tylko to, że każda linia ma tylko jedno słowo, które rozważam dla celów krzyżówki.
DTalvacchio
1
Możesz użyć, hexdumpaby sprawdzić dokładnie, jak formatowane są zakończenia linii. Proponuję użyć mój ulubiony format: hexdump -e '"%08_ad (0x%08_ax) "8/1 "%02x "" "8/1 "%02x "' -e '" "8/1 "%_p""|"8/1 "%_p""\n"' masternospaces.txt. Przy wyjściu sprawdź zakończenia linii: 0a-> LF, 0d-> CR.
user43791,

Odpowiedzi:

23

Jak wspomniał @steeldriver, problem może być spowodowany innym stylem zakończenia linii niż grepsię spodziewano.

Aby sprawdzić zakończenia linii

Możesz użyć, hexdumpaby sprawdzić dokładnie, jak formatowane są zakończenia linii. Sugeruję użycie mojego ulubionego formatu:

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

Przy wyjściu sprawdź zakończenia linii: 0a-> LF, 0d-> CR. Bardzo szybki przykład dałby coś takiego:

$ 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..

Uwaga końca linii w formacie dos: 0d 0a.

Aby zmienić zakończenia linii

Możesz zobaczyć tutaj lub tutaj różne metody zmiany zakończeń linii za pomocą różnych narzędzi, ale jednorazowo zawsze możesz użyć vi / vim:

vim masternospaces.txt
:set fileformat=unix
:wq

Grep bez zmiany czegokolwiek

Jeśli chcesz grepdopasować bez względu na zakończenie linii, zawsze możesz określić zakończenia linii w następujący sposób:

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

Jeśli wyświetlana jest pusta linia, możesz sprawdzić, czy rzeczywiście coś dopasowałeś, używając -vopcji cat:

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

Mój osobisty faworyt

Możesz także grep i standaryzować dane wyjściowe, używając sed:

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

gdzie ^Muzyskuje się przez wpisanie Ctrl-V Ctrl-Mna klawiaturze.

Mam nadzieję że to pomoże!

użytkownik43791
źródło
To wszystko jest niezwykle pomocne. Dzisiaj brakuje mi czasu, ale jutro dokładnie to wszystko przejrzę i zobaczę, co się stanie. Jeśli w międzyczasie ktoś z was ma link do twojego ulubionego przewodnika po poleceniach uniksowych, abym mógł nauczyć się trochę, jak to działa, doceniłbym to. Zbieram części tu i tam, ale jeszcze nie znalazłem jednego źródła, do którego będę się zwracał po wyjaśnienia. Dziękujemy wszystkim i sprawdzimy jutro z nadzieją udaną aktualizacją. --D
DTalvacchio,
Szkoda, że ​​ten post nie ma zamknięcia, przynajmniej dla mnie. Nie mogę przez całe życie wymyślić, jak dopasować koniec linii. Jeśli zrobię zrzut heksadecymalny, nie mogę znaleźć ładnej linii kończącej się tak, jak twój przykład powyżej. Nie jestem zaznajomiony z pracą z hexem, więc mogę nie czytać go poprawnie. Próbowałem też [[:cntrl:]]sugerować @ user43791 i nadal nie pasuje do mnie. To nie ma sensu. Używam GNU grep 2.20 i analizuję dane wyjściowe z nDPI, który został zapisany do pliku tekstowego
harperville
@harperville Jeśli ty cat -v yourfile.ext, co widzisz?
user43791
Cóż, nic ekscytującego lub nieoczekiwanego. Tylko treść, jakiej bym się spodziewał. Czy szukasz czegoś konkretnego? Nie mogę tutaj wkleić danych wyjściowych, ale widzę tylko zawartość. Zwykły ol „ASCII tekst angielski” według file.
harperville,
@harperville Brak dodatkowych „^ M” na końcu każdej linii? Czy mógłbyś wkleić kilka pierwszych linii heksa?
user43791,
1

Chociaż możesz używać „standardowej” składni RegEx z grep (jak w odpowiedzi @ user43791 ), grep ma również inne identyfikatory oznaczające granice wejściowe.

Dopasowywanie początku i końca całej linii to \`(backstick) (zamiast ^) i \'(apostrof) (zamiast $).

Więc dla twojego oryginalnego polecenia użyłbyś: grep "COW\'" masternospaces.txt

Notatka: Ważne jest również, aby pamiętać, że ?i +będą traktowane dosłownie, chyba że ucieczka im korzystania \?i \+aby im swoje odpowiedniki selektora RegEx stylu.

Źródło: grepskładnia wyrażeń regularnych

samthecodingman
źródło
grep bierze ^ (karetka) na początek i \ '(apostrof) na koniec
GypsyCosmonaut
1

Innym sposobem na usunięcie \rprzed grep:

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

Podoba mi się to bardzo jasne, ponieważ nie pamiętam takich rzeczy [[:cntrl:]]na długo.

Javier
źródło
-2

„COW $”, gdy bash ustawił parametr dla grep, zostało zinterpretowane jako „COW”, gdzie traktuje „$” jak „”, ponieważ $ jest simbolem ucieczki. gdy nic nie zostało dodane przez $, jest interpretowane jako pusty ciąg przez powłokę bash, więc powinieneś użyć grep 'COW $' masternospaces.txt.

Yangang
źródło
3
ponieważ nie ma ważnego rozszerzenia $, zostanie pozostawione w spokoju przez bash i użyte przez grep. Przekonaj się: echo "COW$"- $nadal tam będzie.
Jeff Schaller
-3

W BSD grep musisz uciec „$” i zawrzeć swój ciąg w podwójnych cudzysłowach:

"COW\$"
użytkownik297403
źródło
1
Yyy ... nie. Nie $będzie on specjalny dla powłoki, ponieważ rzeczy po niej nie są poprawnymi nazwami zmiennych powłoki. Użycie pojedynczych cudzysłowów wokół ciągów statycznych jest lepszym pomysłem, ale tutaj nie ma znaczenia.
Kusalananda