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
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 auniq
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.
grep
meg van adva, de akiack
szolgáltatást használ, a válasz egyszerűenack -ch <pattern>
.