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
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, musiszsort
przed przesłaniem douniq
, 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.
grep
jest określony, ale dla każdego, kto używaack
, odpowiedź brzmi po prostuack -ch <pattern>
.