grep -c je užitečné pro zjištění, kolikrát se v souboru vyskytne řetězec , ale počítá každou událost pouze jednou na řádek. Jak počítat více výskytů na řádek?

Hledám něco elegantnějšího než:

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

Komentáře

  • Vím, že je zadán grep, ale pro každého, kdo používá ack, je odpověď jednoduše ack -ch <pattern>.
  • @KyleStrand Pro mě ack -ch < vzor > počítaly pouze řádky s výskytem a ne s počtem výskytů
  • @MarcKees Při pohledu na manuálovou stránku to zní jako správné chování. Děkujeme, že jste na to upozornili!

Odpověď

grep „s -o vypíše pouze shody, ignoruje řádky; wc je může spočítat:

grep -o "needle" file | wc -l 

Tímto způsobem se budou shodovat také „jehly“ nebo „víceřadé“.

Chcete-li vyhledat pouze jednotlivá slova, použijte jeden z následujících příkazů:

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

Komentáře

  • Upozorňujeme, že to vyžaduje GNU grep (Linux, Cygwin, FreeBSD, OSX).
  • @wag Jaká magie funguje \b a \B děláte to?
  • @Geek \ b odpovídá hranici slova, \ B odpovídá NE hranici slova. Výše uvedená odpověď by byla správnější, kdyby používala \ b na obou koncích.
  • Pro počet výskytů na řádek kombinujte s možností grep -n a uniq -c … grep -no ' \ < jehla \ > ' soubor | uniq -c
  • @jameswarren uniq odstraní pouze sousední identické řádky, musíte sort před podáním do uniq pokud si nejste jisti, že duplikáty budou vždy bezprostředně sousedit.

Odpovědět

Pokud máte GNU grep (vždy v systému Linux a Cygwin, příležitostně jinde), můžete spočítat výstupní řádky z grep -o : grep -o needle | wc -l.

S Perlem je několik způsobů, které považuji za elegantnější než ten váš (i po jeho opraveno ).

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" 

Pouze u nástrojů POSIX je jedním z přístupů, pokud je to možné, rozdělení vstup do řádků s jednou shodou, než je předáte grep. Pokud například hledáte celá slova, pak každý neslovný znak změňte na nový řádek.

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

Jinak neexistuje standardní příkaz, který by to udělal konkrétní zpracování textu, takže se musíte obrátit na sed (pokud jste masochista) nebo 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 

Zde je jednodušší řešení pomocí sed a grep, který funguje pro řetězce nebo dokonce regulární výrazy podle knihy, ale v několika rohových případech s ukotvenými vzory selže ( např najde dva výskyty ^needle nebo \bneedle v needleneedle).

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

Všimněte si, že ve výše uvedených substitucích sed jsem použil \n nový řádek. To je v části se vzorkem standardní, ale v náhradním textu z důvodu přenositelnosti nahraďte zpětné lomítko-nový řádek za \n.

Odpověď

Pokud jste stejně jako já vlastně chtěli „oba; každý přesně jednou“, (to je vlastně „buď; dvakrát“), pak je to jednoduché :

grep -E "thing1|thing2" -c 

a zkontrolujte výstup 2.

Výhodou tohoto přístupu (pokud přesně jednou je to, co chcete) je to, že se snadno škáluje.

Komentáře

  • I ' si nejste jisti, zda se ' skutečně kontrolujete, ' se zobrazí jen jednou? Všichni ' hledáme, že jedno z těchto slov existuje alespoň jednou.
  • Toto by měla být přijatá odpověď. Není třeba používat wc -l, grep má integrovanou možnost počítat věci a je dokonce pojmenována jako zřejmá jako -c pro „count“!

odpověď

další řešení využívající awk a needle jako oddělovač polí:

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

Pokud chcete najít shodu needle následovaný interpunkcí, změňte odpovídajícím způsobem oddělovač polí, tj.

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

Nebo použijte třídu: [^[:alnum:]], aby zahrnoval všechny znaky, které nejsou alfa.

Komentáře

  • Upozorňujeme, že to vyžaduje awk, který podporuje oddělovače polí regexp (například GNU awk).

Odpověď

Toto je moje čisté řešení 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 

Odpověď

Váš příklad vytiskne pouze počet výskytů na řádek, nikoli celkový počet v souboru. Pokud to je to, co chcete, může něco takového fungovat:

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

Komentáře

  • Vy mají pravdu – můj příklad počítá pouze výskyty v prvním řádku.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *