grep -c jest przydatne do znajdowania, ile razy ciąg występuje w pliku , ale liczy każde wystąpienie tylko raz w wierszu. Jak policzyć wiele wystąpień w wierszu?

Szukam czegoś bardziej eleganckiego niż:

perl -e "$_ = <>; print scalar ( () = m/needle/g ), "\n"" 

Komentarze

  • Wiem, że grep jest określony, ale dla każdego, kto używa ack, odpowiedź brzmi po prostu ack -ch <pattern>.
  • @KyleStrand Dla mnie ACK -ch < wzór > policzył tylko wiersze z wystąpieniami, a nie liczbę wystąpień.
  • @MarcKees Patrząc na stronę podręcznika, brzmi to jak prawidłowe zachowanie. Dziękuję za zwrócenie uwagi!

Odpowiedź

grep „s -o wyświetli tylko dopasowania, ignorując wiersze; wc może je policzyć:

grep -o "needle" file | wc -l 

To również pasuje do „igieł” lub „wieloigłowych”.

Aby dopasować tylko pojedyncze słowa, użyj jednego z następujących poleceń:

grep -ow "needle" file | wc -l grep -o "\bneedle\b" file | wc -l grep -o "\<needle\>" file | wc -l 

Komentarze

  • Zauważ, że wymaga to GNU grep (Linux, Cygwin, FreeBSD, OSX).
  • @wag Co robi magia \b i \B zrobić tutaj?
  • @ Geek \ b dopasowuje granicę słowa, \ B NIE pasuje do granicy słowa. Powyższa odpowiedź byłaby bardziej poprawna, gdyby używała \ b na obu końcach.
  • Aby uzyskać liczbę wystąpień w wierszu, połącz z opcją grep -n i uniq -c … grep -no ' \ < needle \ > ' plik | uniq -c
  • @jameswarren uniq usuwa tylko sąsiednie identyczne linie, musisz sort przed przesłaniem do uniq, jeśli nie masz jeszcze pewności, że duplikaty zawsze będą bezpośrednio sąsiadować.

Odpowiedź

Jeśli masz GNU grep (zawsze w Linuksie i Cygwin, czasami gdzie indziej), możesz policzyć wiersze wyjściowe z grep -o : grep -o needle | wc -l.

Oto kilka sposobów, w jakie Perl jest bardziej elegancki niż twój (nawet po naprawiono ).

perl -lne "END {print $c} map ++$c, /needle/g" perl -lne "END {print $c} $c += s/needle//g" perl -lne "END {print $c} ++$c while /needle/g" 

W przypadku tylko narzędzi POSIX, jednym podejściem, jeśli to możliwe, jest podzielenie wprowadzaj do wierszy z pojedynczym dopasowaniem przed przekazaniem go do grep. Na przykład, jeśli szukasz całych słów, najpierw zamień każdy znak niebędący słowem w nową linię.

# equivalent to grep -ow "needle" | wc -l tr -c "[:alnum:]" "[\n*]" | grep -c "^needle$" 

W przeciwnym razie nie ma standardowego polecenia do zrobienia tego jest szczególnym przetwarzaniem tekstu, więc musisz przejść do seda (jeśli jesteś masochistą) lub awk.

awk "{while (match($0, /set/)) {++c; $0=substr($0, RSTART+RLENGTH)}} END {print c}" sed -n -e "s/set/\n&\n/g" -e "s/^/\n/" -e "s/$/\n/" \ -e "s/\n[^\n]*\n/\n/g" -e "s/^\n//" -e "s/\n$//" \ -e "/./p" | wc -l 

Oto prostsze rozwiązanie przy użyciu ( na przykład znajduje dwa wystąpienia ^needle lub \bneedle w needleneedle).

sed "s/needle/\n&\n/g" | grep -cx "needle" 

Zauważ, że w powyższych podstawieniach seda użyłem \n do oznaczenia nowej linii. Jest to standard w części wzorcowej, ale w tekście zastępczym, w celu zapewnienia przenośności, zamień odwrotny ukośnik-nowa linia zamiast \n.

Odpowiedź

Jeśli tak jak ja faktycznie chciałeś „oba; każdy dokładnie raz”, (to jest właściwie „albo; dwa razy”), to jest to proste :

grep -E "thing1|thing2" -c 

i sprawdź wynik 2.

Zalety tego podejścia (jeśli dokładnie raz jest tym, czego chcesz), to łatwość skalowania.

Komentarze

  • I ' Nie jestem pewien, czy ' sprawdzasz, czy to ' pojawia się tylko raz? Wszyscy, ' ponownie szukam tego, czy jedno z tych słów istnieje przynajmniej raz.
  • To powinna być zaakceptowana odpowiedź. Nie ma potrzeby używania wc -l, grep ma wbudowaną opcję liczenia rzeczy, a nawet nazywa się ją oczywistą jako -c for „count”!

Answer

Inny rozwiązanie wykorzystujące awk i needle jako separator pól:

awk -F"^needle | needle | needle$" "{c+=NF-1}END{print c}" 

Jeśli chcesz dopasować needle z następującą interpunkcją, zmień odpowiednio separator pól, np.

awk -F"^needle[ ,.?]|[ ,.?]needle[ ,.?]|[ ,.?]needle$" "{c+=NF-1}END{print c}" 

Lub użyj klasy: [^[:alnum:]], aby objąć wszystkie znaki inne niż alfa.

Komentarze

  • Zauważ, że wymaga to awk, który obsługuje separatory pól wyrażeń regularnych (np. GNU awk).

Odpowiedź

To jest moje czyste rozwiązanie bash

#!/bin/bash B=$(for i in $(cat /tmp/a | sort -u); do echo "$(grep $i /tmp/a | wc -l) $i" done) echo "$B" | sort --reverse 

Odpowiedź

Twój przykład wypisuje tylko liczbę wystąpień w wierszu, a nie całkowitą liczbę w pliku. Jeśli tego chcesz, coś takiego może zadziałać:

perl -nle "$c+=scalar(()=m/needle/g);END{print $c}" 

Komentarze

  • Ty mają rację – mój przykład liczy tylko wystąpienia w pierwszej linii.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *