grep -c on hyödyllistä selvittää, kuinka monta kertaa merkkijono esiintyy tiedostossa , mutta se laskee jokaisen esiintymän vain kerran riviä kohden. Kuinka lasketaan useita esiintymiä riviä kohti?

Etsin jotain tyylikkäämpää kuin:

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

kommentit

  • Tiedän, että grep on määritetty, mutta kaikille, jotka käyttävät ack, vastaus on yksinkertaisesti ack -ch <pattern>.
  • @KyleStrand Minulle ack -ch < kuvio > laskivat vain rivit esiintymillä eikä esiintymien lukumäärällä
  • @MarcKees Man -sivua katsellen kuulostaa oikealta käyttäytymiseltä. Kiitos huomautuksesta!

vastaus

grep ”s -o tuottaa vain ottelut ohittamatta rivejä; wc voi laskea ne:

grep -o "needle" file | wc -l 

Tämä vastaa myös ”neuloja” tai ”monineuloja”.

Vain yksittäisten sanojen sovittamiseksi käytä yhtä seuraavista komennoista:

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

Kommentit

  • Huomaa, että tämä vaatii GNU grep: n (Linux, Cygwin, FreeBSD, OSX).
  • @wag Mitä taikaa \b ja \B tehdä tässä?
  • @Geek \ b vastaa sanarajaa, \ B vastaa EI sanarajaa. Yllä oleva vastaus olisi oikeampi, jos siinä käytettäisiin \ b molemmissa päissä.
  • Yhdistä rivien kohdalla tapahtumien lukumäärään grep -n-vaihtoehto ja uniq -c … grep -no ' \ < neula \ > ' tiedosto | uniq -c
  • @jameswarren uniq poistaa vain vierekkäiset identtiset viivat, sinun on sort ennen syötystä ryhmään uniq jos et ole vielä varma, että kaksoiskappaleet ovat aina vierekkäin.

Vastaa

Jos sinulla on GNU grep (aina Linuxissa ja Cygwinissä, joskus muualla), voit laskea lähtörivit riviltä grep -o : grep -o needle | wc -l.

Perlillä tässä on muutama tapa, joka on mielestäni tyylikkäämpi kuin sinun (jopa sen jälkeen, kun se on korjattu ).

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" 

Vain POSIX-työkaluilla yksi lähestymistapa, jos mahdollista, on jakaa kirjoita riveihin yhdellä ottelulla, ennen kuin välität sen grepiin. Jos esimerkiksi etsit kokonaisia sanoja, tee ensin jokaisesta ei-sanamerkistä uusi rivi.

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

Muussa tapauksessa ei ole tavallista komentoa tehdä tätä Erityistä vähän tekstinkäsittelyä, joten sinun on käännyttävä sed (jos olet masokisti) tai 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 

Tässä ”yksinkertaisempi ratkaisu sed ja grep, jotka toimivat merkkijonojen tai jopa kirjan säännöllisten lausekkeiden kanssa, mutta epäonnistuvat joissakin kulmatapauksissa, joissa on ankkuroituja kuvioita ( esimerkiksi se löytää kaksi esiintymää: ^needle tai \bneedle (needleneedle).

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

Huomaa, että yllä olevissa sed-korvauksissa käytin \n -merkintää uudelle riville. Tämä on vakio malliosassa, mutta siirrettävyyden korvaavassa tekstissä korvaa \n: n backslash-newline.

Vastaa

Jos haluaisit minun tavoin ”molemmat; kumpikin täsmälleen kerran”, (tämä on oikeastaan ”joko; kahdesti”), niin se on yksinkertaista :

grep -E "thing1|thing2" -c 

ja tarkista ulostulo 2.

Tämän lähestymistavan edut (jos tarkalleen kerran on mitä haluat) on, että se skaalautuu helposti.

Kommentit

  • I ' en ole varma, oletko ' tarkistanut tosiasiallisesti sen, että ' näytät vain kerran? Kaikki sinä ' Etsimässä on, että jompikumpi näistä sanoista on olemassa ainakin kerran.
  • Tämän pitäisi olla hyväksytty vastaus. Ei tarvitse käyttää wc -l, grep on sisäänrakennettu vaihtoehto laskea asioita, ja se on jopa nimetty ilmeiseksi nimellä -c ”laskea”!

Vastaa

Toinen ratkaisu, jossa kentän erottimena käytetään awk ja needle:

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

Jos haluat sovittaa needle ja sen jälkeen välimerkit, vaihda kentän erotin vastaavasti eli

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

Tai käytä luokkaa: [^[:alnum:]] sisältää kaikki muut kuin aakkoset.

Kommentit

  • Huomaa, että tämä edellyttää awk: tä, joka tukee regexp-kentän erottimia (kuten GNU awk).

vastaus

Tämä on puhdas bash-ratkaisuni

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

Vastaus

Esimerkki tulostaa vain esiintymien määrän riviä kohden, ei tiedoston kokonaismäärää. Jos se on mitä haluat, jotain tällaista saattaa toimia:

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

Kommentit

  • Sinä ovat oikeassa – esimerkkini laskee vain esiintymät ensimmäisellä rivillä.

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *