grep -c hasznos annak megállapításához, hogy egy karakterlánc hányszor fordul elő egy fájlban , de soronként csak egyszer számolja az egyes előfordulásokat. Hogyan számolhatok soronként több előfordulást?

Valami elegánsabbat keresek, mint:

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

Megjegyzések

  • Tudom, hogy grep meg van adva, de aki ack szolgáltatást használ, a válasz egyszerűen ack -ch <pattern>.
  • @KyleStrand Számomra ack -ch < minta > csak az előfordulásokat tartalmazó sorokat számolta, az előfordulások számát nem.
  • @MarcKees A man oldalt nézve ez helyes viselkedésnek tűnik. Köszönjük, hogy felhívta a figyelmét erre!

Válasz

grep “s -o csak az egyezéseket adja ki, a sorokat figyelmen kívül hagyva; wc meg tudja számlálni őket:

grep -o "needle" file | wc -l 

Ez egyezik a “tűkkel” vagy a “több tűvel” is.

Csak az egyes szavak megfeleltetéséhez használja a következő parancsok egyikét:

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

Megjegyzések

  • Ne feledje, hogy ehhez GNU grep szükséges (Linux, Cygwin, FreeBSD, OSX).
  • @wag Milyen varázslatokat csinál \b és \B csináld itt?
  • @Geek \ b egyezik a szóhatárral, \ B NEM egy szóhatárral. A fenti válasz helyesebb lenne, ha mindkét végén használná a \ b elemet.
  • A soronkénti előfordulások számához kombináljuk a grep -n opcióval és az uniq -c … grep -no ' \ < tű \ > ' fájl | uniq -c
  • @jameswarren uniq csak a szomszédos azonos vonalakat távolítja el, sort szükséges a uniq ha még nem biztos abban, hogy a másolatok mindig közvetlenül szomszédosak lesznek.

Válasz

Ha van GNU grep (mindig Linuxon és Cygwin-en, alkalmanként máshol), akkor megszámolhatja a kimeneti sorokat a grep -o : grep -o needle | wc -l.

A Perl-lel itt íme néhány módszer, amelyet elegánsabbnak találok, mint a tiéd (még azután is, hogy “s javítva ).

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" 

Csak POSIX eszközökkel egy megközelítés, ha lehetséges, a felosztás bevitele a sorokba egyetlen egyezéssel, mielőtt átadná a grepnek. Például, ha egész szavakat keres, akkor minden nem szóból álló karaktert először új vonallá alakítson.

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

Ellenkező esetben nincs szabványos parancs erre A szövegfeldolgozás sajátos bitje, így a sed (ha mazochista vagy) vagy awk oldalra kell fordulnia.

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 

Itt “egyszerűbb megoldás sed és grep, amelyek karakterláncokhoz vagy akár könyv szerinti reguláris kifejezésekhez is használhatók, de néhány sarok esetben horgonyzott mintákkal kudarcot vallanak ( például a ^needle vagy \bneedle két előfordulását megtalálja a needleneedle).

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

Ne feledje, hogy a fenti sed helyettesítéseknél az \n szót használtam új sorra. Ez szokásos a minta részben, de a helyettesítő szövegben a hordozhatóság érdekében a \n szót a backslash-newline helyettesíti.

Válasz

Ha, mint én, valóban “mindkettőt; mindkettőt pontosan egyszerre kívánta”, (ez valójában “vagy; kétszer”), akkor ez egyszerű :

grep -E "thing1|thing2" -c 

és ellenőrizze a kimenetet 2.

A megközelítés előnyei (ha pontosan egyszer az, amire vágysz), az az, hogy könnyen méretezhet.

Megjegyzések

  • I ' nem vagyok benne biztos, hogy ' valóban ellenőrzi-e ' csak egyszer jelenik meg? Mindannyian ' arra keresem, hogy e szavak egyike legalább egyszer létezik.
  • Ez legyen az elfogadott válasz. Nem kell használni a , grep beépített lehetősége van a dolgok számlálására, sőt nyilvánvalónak is nevezik mint -c a „számláláshoz”!

Válasz

Másik megoldás awk és needle mezőelválasztóként:

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

Ha meg akarja egyezni a needle és írásjelek, ennek megfelelően változtassa meg a mezőelválasztót, azaz

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

Vagy használja a következő osztályt: [^[:alnum:]] az összes nem alfa karakter befogadásához.

Megjegyzések

  • Ne feledje, hogy ehhez egy olyan awk szükséges, amely támogatja a regexp mezőelválasztókat (például a GNU awk).

Válasz

Ez a tiszta bash megoldásom

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

Válasz

A példád csak a soronkénti előfordulások számát nyomtatja ki, a fájlban szereplő összeget nem. Ha ezt szeretné, akkor valami ilyesmi működhet:

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

megjegyzések

  • Ön igazuk van – példám csak az első sorban számolja az előfordulásokat.

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük