it-swarm-eu.dev

Spočítejte celkový počet výskytů pomocí grep

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

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

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

grep's -o vydá pouze zápasy, ignorující řádky; wc je může spočítat:

grep -o 'needle' file | wc -l

To se také bude shodovat s „jehlami“ nebo „vícečetnými“.

Ke shodě pouze jednotlivých slov 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
352
wag

Pokud máte GNU grep (vždy v systémech 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ů, jak se mi zdá elegantnější než ten váš (i poté, co je 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'

Jediným přístupem, pokud je to možné, pouze pomocí nástrojů POSIX, je před vstupem do grepu rozdělit vstup na řádky s jedinou shodou. Například, pokud hledáte celá slova, pak nejprve proměňte každý znak mimo Word na nový řádek.

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

Jinak neexistuje žádný standardní příkaz k provedení tohoto konkrétního kousku 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 v knize, ale selže v několika rohových případech s ukotvenými vzory (např. Najde dva výskyty ^needle nebo \bneedle in 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 znamená nový řádek. To je standardní v části vzoru, ale v nahrazujícím textu je pro přenositelnost nahrazeno znakem zpětného lomítka-nový řádek za \n.

Pokud jste stejně jako já skutečně 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 mění měřítko.

5
OJFord

Další řešení používající awk a needle jako oddělovač pole:

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

Pokud chcete porovnat needle následovanou interpunkcí, změňte odpovídajícím způsobem oddělovač pole, tzn.

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

Nebo použijte třídu: [^[:alnum:]] pro zahrnutí všech ne-alfa znaků.

3
ripat

To je moje čisté bash řešení

#!/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
1
Felipe

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

Perl -nle '$c+=scalar(()=m/needle/g);END{print $c}' 
1
jsbillings