grep -c är användbart för att hitta hur många gånger en sträng förekommer i en fil , men det räknar bara varje förekomst en gång per rad. Hur räknar jag flera förekomster per rad?

Jag letar efter något mer elegant än:

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

Kommentarer

  • Jag vet att grep anges, men för alla som använder ack är svaret helt enkelt ack -ch <pattern>.
  • @KyleStrand För mig ack -ch < mönster > räknade bara raderna med förekomster och inte antalet förekomster
  • @MarcKees Tittar på mansidan, det låter som rätt beteende. Tack för att du påpekade det!

Svar

grep ”s -o matar bara ut matchningarna och ignorerar rader; wc kan räkna dem:

grep -o "needle" file | wc -l 

Detta kommer också att matcha ”nålar” eller ”multinedle”.

Använd en av följande kommandon för att matcha enstaka ord:

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

Kommentarer

  • Observera att detta kräver GNU grep (Linux, Cygwin, FreeBSD, OSX).
  • @wag Vilken magi gör \b och \B gör här?
  • @Geek \ b matchar en ordgräns, \ B matchar INTE en ordgräns. Svaret ovan skulle vara mer korrekt om det användes \ b i båda ändar.
  • För ett antal förekomster per rad, kombinera med grep -n-alternativet och uniq -c … grep -no ' \ < nål \ > ' fil | uniq -c
  • @jameswarren uniq tar bara bort intilliggande identiska rader, du måste sort innan du matar till uniq om du inte redan är säker på att dubbletter alltid kommer att vara direkt intill.

Svar

Om du har GNU grep (alltid på Linux och Cygwin, ibland någon annanstans) kan du räkna utgångslinjerna från grep -o : grep -o needle | wc -l.

Med Perl är det här några sätt jag tycker är elegantare än din (även efter det ”s fixad ).

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" 

Med endast POSIX-verktyg är en metod, om möjligt, att dela upp mata in rader med en enda matchning innan du skickar den till grep. Till exempel, om du letar efter hela ord, förvandlar du först alla icke-ordstecken till en ny rad.

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

Annars finns det inget standardkommando att göra detta s speciella bit textbehandling, så du måste vända dig till sed (om du är en masochist) eller 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 

Här ”är en enklare lösning med sed och grep, som fungerar för strängar eller till och med böcker, reguljära uttryck men misslyckas i några hörnfall med förankrade mönster ( t.ex den hittar två förekomster av ^needle eller \bneedle i needleneedle).

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

Observera att i sed-substitutionerna ovan använde jag \n för att betyda en ny rad. Detta är standard i mönsterdelen, men i ersättningstexten, för bärbarhet, ersätt backslash-newline för \n.

Svar

Om du, precis som jag, verkligen ville ha ”båda, var och en exakt en gång”, (detta är faktiskt ”antingen; två gånger”) så är det enkelt :

grep -E "thing1|thing2" -c 

och leta efter utdata 2.

Fördelen med denna metod (om exakt en gång är vad du vill ha) är att den enkelt skalas.

Kommentarer

  • I ' Är jag inte säker på att du ' faktiskt kontrollerar att den ' bara visas en gång? Allt du ' att leta efter finns att något av dessa ord existerar minst en gång.
  • Detta borde vara det accepterade svaret. Inget behov av att använda wc -l, grep har ett inbyggt alternativ för att räkna saker, och det kallas till och med som självklart som -c för ”count”!

Svar

Ytterligare lösning med awk och needle som fältseparator:

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

Om du vill matcha needle följt av skiljetecken, ändra fältseparatorn i enlighet därmed dvs.

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

Eller använd klassen: [^[:alnum:]] för att omfatta alla icke-alfabetecken.

Kommentarer

  • Observera att detta kräver en awk som stöder regexp-fältavgränsare (t.ex. GNU awk).

Svar

Detta är min rena bash-lösning

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

Svar

Ditt exempel skriver bara ut antalet förekomster per rad och inte summan i filen. Om det är vad du vill kan något liknande fungera:

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

Kommentarer

  • Du har rätt – mitt exempel räknar bara förekomsten i första raden.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *