Jak sprawić, by grep pasował tylko wtedy, gdy pasuje cała linia?

104

Mam te:

$ cat a.tmp
ABB.log
ABB.log.122
ABB.log.123

Chciałem znaleźć dokładne dopasowanie do ABB.log.

Ale kiedy to zrobiłem

$ grep -w ABB.log a.tmp
ABB.log
ABB.log.122
ABB.log.123

pokazuje je wszystkie.

Czy mogę uzyskać to, co chciałem, używając grep?

Johnyy
źródło

Odpowiedzi:

105

Po prostu określ kotwice regexp.

grep '^ABB\.log$' a.tmp
user562374
źródło
2
Potrzebne są oba kotwice (^ i $).
user562374
2
Niezłe! A jeśli używam wyrażenia regularnego do dopasowywania z pliku? "grep -f patterns a.tmp" ??
green69
@ green69 Kilka lat później, ale możesz użyć seda, aby dodać kotwice przed przekazaniem wzorów do grep:sed -r "s/^(.*)$/^\1$/" patterns.txt | egrep -f - a.tmp
Randoms
156
grep -Fx ABB.log a.tmp

Ze strony podręcznika grep:

-F, --fixed-strings
Interpretuje WZÓR jako (listę) ustalonych ciągów
-x, --line-regexp
Wybierz tylko te dopasowania, które dokładnie pasują do całej linii.

John Kugelman
źródło
2
niestety nie był w stanie użyć -F.
Johnyy
@Johnyy No -F? jesteś na Solarisie? Jeśli tak, użyj/usr/xpg4/bin/grep
Scrutinizer
9
Używam grepwewnątrz skryptu bash i ta opcja jest lepsza niż użycie wyrażenia regularnego, jak sugeruje zaakceptowana odpowiedź. Ponieważ w zmiennej, której szukam (lubię .), mam jakiś znak specjalny i nie muszę ich wymykać podczas używania polecenia.
Gustavo Straube
1
najlepsza odpowiedź IMO, ponieważ zezwala na znaki specjalne bez ucieczki
ReneGAED
1
Jest to lepsze, ponieważ działa również ze zmiennymi.
ybenjira
23

Oto, co robię, chociaż używanie kotwic jest najlepszym sposobem:

grep -w "ABB.log " a.tmp
PranavKN
źródło
Tak jak ten ... zwróci Dopasowanie pierwszej linii
user765443
1
Wymaga to spacji później ABB.log, co nie jest przypadkiem ogólnym, tj. Zwykle zawiedzie.
Jahid
3

Większość sugestii kończy się niepowodzeniem, jeśli występuje tylko jedna wiodąca lub końcowa spacja, która ma znaczenie, jeśli plik jest edytowany ręcznie. W takim przypadku byłoby to mniej podatne:

grep '^[[:blank:]]*ABB\.log[[:blank:]]*$' a.tmp

Prosta pętla while-read w powłoce zrobiłaby to niejawnie:

while read file
do 
  case $file in
    (ABB.log) printf "%s\n" "$file"
  esac
done < a.tmp
Scrutinizer
źródło
2

podobnie z awk

 awk '/^ABB\.log$/' file
ghostdog74
źródło
1

Zamierzam dodać dodatkowe wyjaśnienia dotyczące prób OP i innych odpowiedzi.

Możesz również użyć rozwiązania Johna Kugelmana w następujący sposób:

grep -x "ABB\.log" a.tmp

cytowanie łańcucha i unikanie znaku kropki ( .) sprawia, że -Fflaga nie jest już potrzebna .

Musisz uciec od .(kropki) (ponieważ pasuje do dowolnego znaku (nie tylko .), jeśli nie jest zmieniony) lub użyć -Fflagi z grep. -Fflaga sprawia, że ​​jest to stały ciąg (nie wyrażenie regularne).

Jeśli nie podasz cudzysłowu, możesz potrzebować podwójnego odwrotnego ukośnika, aby uniknąć kropki ( .):

grep -x ABB\\.log a.tmp


Test:

$ echo "ABBElog"|grep -x  ABB.log
ABBElog #matched !!!
$ echo "ABBElog"|grep -x  "ABB\.log"
#returns empty string, no match


Uwaga:

  1. -x siły, aby dopasować całą linię.
  2. Odpowiedzi używające bez zmiany znaczenia .bez -Fflagi są błędne.
  3. Możesz uniknąć -xzmiany, owijając ciąg wzorca za pomocą ^i $. W takim przypadku upewnij się, że nie używasz -F, zamiast tego ucieknij przed ., ponieważ -Funiemożliwi to interpretację wyrażeń regularnych ^i $.


EDYCJA: (Dodanie dodatkowego wyjaśnienia w odniesieniu do @hakre):

Jeśli chcesz dopasować ciąg zaczynający się od -, powinieneś użyć --z grep. Cokolwiek nastąpi, --zostanie przyjęte jako dane wejściowe (nie opcja).

Przykład:

echo -f |grep -- "-f"     # where grep "-f" will show error
echo -f |grep -F -- "-f"  # whre grep -F "-f" will show error
grep "pat" -- "-file"     # grep "pat" "-file" won't work. -file is the filename
Jahid
źródło
Czy rzeczywiście doświadczyłeś, że w twoim przypadku brakowało -F? Jeśli tak, czy możesz powiedzieć, który to był przypadek?
hakre
@hakre Czy całkowicie przeczytałeś moją odpowiedź? Wyjaśniłem (dość wyraźnie), dlaczego -Fnie będzie potrzebne, jeśli .zostanie prawidłowo uciec.
Jahid
Pewnie. Jasne, tylko pytam: czy był -Fdostępny, kiedy to pisałeś? Jeśli nie, z jakiego systemu korzystałeś? Do tej pory nie mogłem znaleźć tych informacji w Twojej odpowiedzi, co nawet teraz ma miejsce, gdy ponownie ją czytam. Tak naprawdę, co najmniej dwa razy przeczytałem twoją odpowiedź. ;)
hakre
@hakre Oczywiście -Fbyło dostępne. (Powiedziałem: „lub użyj -Fflagi z grep”)
Jahid
Dzięki za wgląd. Pozostaje tylko jedno małe pytanie: jeśli -Fjest odpowiedź, po co zawracać sobie głowę ucieczką? Jaka jest Twoja opinia na ten temat?
hakre
1

To działało dobrze, gdy próbowałem zrobić coś podobnego:

grep -F ABB.log a.tmp
Fred Christophe
źródło
-1
    $ cat venky
    ABB.log
    ABB.log.122
    ABB.log.123

    $ cat venky | grep "ABB.log" | grep -v "ABB.log\."
    ABB.log
    $

    $ cat venky | grep "ABB.log.122" | grep -v "ABB.log.122\."
    ABB.log.122
    $
user2173461
źródło
1
Spowoduje to również dopasowanie do plików kończących się na ABB.log, a kropki powinny zostać zmienione.
Scrutinizer
-1

U mnie działa :

grep "\bsearch_word\b" text_file > output.txt  

\b wskazuje / wyznacza granice.

Wydaje się, że działa dość szybko

Surya
źródło
To również pasuje do każdego wiersza, który zawiera search_wordoddzielone granicami słów. Na przykład pasowałoby do wiersza „foo search_word bar”.
Rohan Singh
-2

Tak jest w przypadku HPUX, jeśli zawartość plików ma spację między słowami, użyj tego:

egrep "[[:space:]]ABC\.log[[:space:]]" a.tmp

user3114790
źródło
OP chciał dopasować całą linię, a nie słowo rozdzielone spacjami w linii.
Keith Thompson
-3

Wolałbym:

str="ABB.log"; grep -E "^${str}$" a.tmp

Twoje zdrowie

Bartosz
źródło
To będzie meczABBxlog
Keith Thompson
-3

Potrzebowałem tej funkcji, ale chciałem też mieć pewność, że nie zwracam wierszy z prefiksem przed ABB.log:

  • ABB.log
  • ABB.log.122
  • ABB.log.123
  • 123ABB.log

grep "\WABB.log$" -w a.tmp
Jonathan
źródło
To będzie pasować tylko wtedy, gdy interlinia \Wjest spełniona, co jest dowolnym znakiem innym niż biały znak, więc xABBxlog.
bschlueter