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
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ítesort
před podáním douniq
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.
grep
, ale pro každého, kdo používáack
, je odpověď jednodušeack -ch <pattern>
.