grep dziwne zachowanie za pomocą pojedynczych liter

10

Usuwam słowa stop z tekstu, z grubsza używając tego kodu

Mam następujące

$ cat file
file
types
extensions

$ cat stopwords
i
file
types

grep -vwFf stopwords file

Oczekuję wyniku: extensions

ale dostaję (myślę, że niepoprawny)

file
extensions

To tak, jakby słowo filezostało pominięte w pliku stopwords. Teraz tutaj jest nieco cool: gdybym zmodyfikować plik odrzucanych słów, zmieniając jedno słowo / literę ina pierwszej linii, do jakiegokolwiek innego ASCII litery oprócz f, i, l, e, a następnie to samo polecenie grep daje mi inny i prawidłowego wyniku extensions.

Co tu się dzieje i jak to naprawić?

Używam grep (BSD grep) 2.5.1-FreeBSD na bash dla systemu Mac OSX GNU, wersja 4.4.12 (1)

Tim
źródło
Może chcesz użyć -xprzełącznika do wyrażenia regularnego wiersza zamiast -wsłowa? Myślę jednak, że -Fzmiana anuluje którekolwiek z nich lub odwrotnie.
jesse_b
grep (GNU grep) 3.1 działa zgodnie z oczekiwaniami.
Hauke ​​Laging
Powtórzyłem to. Kolejny punkt odniesienia: ustawienie iwzorca na drugi zamiast pierwszego wzorca w stopwordspliku również zmienia zachowanie.
JdeBP
Nie mogę odtworzyć zachowania w OpenBSD 6.2 z natywnym grepani z GNU grep3.1.
Kusalananda

Odpowiedzi:

13

Był to błąd bsdgrepzwiązany ze zmienną, która śledzi część bieżącego wiersza do skanowania, która jest zastępowana kolejnymi wywołaniami do silnika dopasowywania wyrażeń regularnych, gdy w grę wchodzi wiele wzorców.

lokalna poprawka

Można obejść ten problem w pewnym stopniu, nie używając -wopcji, która opiera się na tej zmiennej do poprawnego działania, a zatem nie działa, ale zamiast tego używa rozszerzeń wyrażeń regularnych, które pasują do początku i końca słów, dzięki czemu stopwordsplik wygląda jak:

\ <i \>
\ <plik \>
\ <typy \>

To obejście wymaga również, aby nie używać tej -Fopcji.

Należy zauważyć, że udokumentowane regularne elementy ekspresyjne [[:<:]]i [[:>:]]że re_formatinstrukcja mówi pan o będzie nie działa tutaj. Wynika to z faktu, że skompilowana biblioteka wyrażeń regularnych bsdgrepma włączoną obsługę kompatybilności wyrażeń regularnych GNU. To kolejny błąd, który podobno został naprawiony.

poprawka serwisowa

Ten błąd został naprawiony na początku tego roku. Ta poprawka nie została jeszcze wprowadzona do wersji STABILNEJ lub WYDAWNEJ FreeBSD, ale podobno jest w BIEŻĄCEJ.

Aby pobrać to do wersji MacOS grep, która pochodzi z FreeBSD bsdgrep, skonsultuj się z Apple. ☺

Dalsza lektura

JdeBP
źródło
Fajnie i dziękuję za zgłoszenie tego wcześniej. Dla mnie ta odpowiedź byłaby jeszcze bardziej fascynująca, gdyby zacytowała błędny kod.
dhag
1

Ten kod:

pl " Input data file data1 and stopwords file data2:"
head data1 data2

pl " Expected output:"
cat $E

pl " Results, grep:"
# grep -vwFf stopwords file
grep -vwFf data2 data1

pl " Results, cgrep:"
cgrep -x1 -vFf data2 data1

produkuje:

-----
 Input data file data1 and stopwords file data2:
==> data1 <==
file
types
extensions

==> data2 <==
i
file
types

-----
 Expected output:
extensions

-----
 Results, grep:
file
extensions

-----
 Results, cgrep:
extensions

W systemie takim jak:

OS, ker|rel, machine: Apple/BSD, Darwin 16.7.0, x86_64
Distribution        : macOS 10.12.6 (16G29), Sierra
bash GNU bash 3.2.57

Więcej szczegółów na temat cgrep, dostępnych poprzez brew oraz z sourceforge:

cgrep   shows context of matching patterns found in files (man)
Path    : ~/executable/cgrep
Version : 8.15
Type    : Mach-O64-bitexecutablex86_64 ...)
Home    : http://sourceforge.net/projects/cgrep/ (doc)

na zdrowie, drl

drl
źródło
właśnie dostałem nowego grepa.
Tim
@Tim - Mam nadzieję, że cgrep okaże się tak przydatny jak ja. Szybkość testów, które przeprowadziłem, z grubsza dorównuje GNU grep, a funkcje „kontekstu / okienkowania” są bardzo przydatne. Łatwo też buduje na systemach Linux ... na zdrowie, drl
drl