grep -c este util pentru a găsi de câte ori apare un șir într-un fișier , dar contează fiecare apariție o singură dată pe linie. Cum să număr mai multe apariții pe linie?

Caut ceva mai elegant decât:

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

Comentarii

  • Știu că este specificat grep, dar pentru oricine folosește ack, răspunsul este pur și simplu ack -ch <pattern>.
  • @KyleStrand Pentru mine ack -ch < model > a numărat doar liniile cu apariții și nu numărul de apariții
  • @MarcKees Privind pagina manuală, sună comportamentul corect. Vă mulțumim că ați arătat acest lucru!

Răspuns

grep „s -o va afișa doar potrivirile, ignorând liniile; wc le poate număra:

grep -o "needle" file | wc -l 

Acest lucru se va potrivi și cu „ace” sau cu „multiintroducere”.

Pentru a se potrivi doar cuvinte simple, utilizați una dintre următoarele comenzi:

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

Comentarii

  • Rețineți că acest lucru necesită GNU grep (Linux, Cygwin, FreeBSD, OSX).
  • @wag Ce magie face \b și \B faci aici?
  • @Geek \ b se potrivește cu o limită de cuvânt, \ B nu se potrivește cu o limită de cuvânt. Răspunsul de mai sus ar fi mai corect dacă s-ar folosi \ b la ambele capete.
  • Pentru un număr de apariții pe linie, combinați cu opțiunea grep -n și uniq -c … grep -no ' \ < ac \ > ' fișier | uniq -c
  • @jameswarren uniq elimină numai liniile identice adiacente, trebuie să sort înainte de a alimenta uniq dacă nu sunteți deja sigur că duplicatele vor fi întotdeauna imediat adiacente.

Răspuns

Dacă aveți GNU grep (întotdeauna pe Linux și Cygwin, ocazional în altă parte), puteți număra liniile de ieșire din grep -o : grep -o needle | wc -l.

Cu Perl, iată câteva moduri pe care le găsesc mai elegante decât ale tale (chiar și după „s fixat ).

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" 

Cu numai instrumente POSIX, o abordare, dacă este posibil, este de a împărți introduceți în linii cu o singură potrivire înainte de a-l trece la grep. De exemplu, dacă căutați cuvinte întregi, transformați mai întâi fiecare caracter care nu este un cuvânt într-o linie nouă.

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

În caz contrar, nu există nicio comandă standard pentru a face asta Procesul special de procesare a textului, deci trebuie să apelați la sed (dacă sunteți masochist) sau 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 

Aici este o soluție mai simplă folosind sed și grep, care funcționează pentru șiruri sau chiar expresii obișnuite din carte, dar eșuează în câteva cazuri de colț cu modele ancorate ( de exemplu găsește două apariții ale ^needle sau \bneedle în needleneedle).

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

Rețineți că în substituțiile sed de mai sus, am folosit \n pentru a însemna o linie nouă. Acest lucru este standard în partea de model, dar în textul de înlocuire, pentru portabilitate, înlocuiți backslash-newline cu \n.

Răspuns

Dacă, ca și mine, ai vrut de fapt „ambele; fiecare exact o dată”, (acesta este de fapt „fie; de două ori”), atunci este simplu :

grep -E "thing1|thing2" -c 

și verificați ieșirea 2.

Beneficiul acestei abordări (dacă exact o dată este ceea ce doriți) este că acesta scară ușor.

Comentarii

  • I ' Nu sunt sigur că ' îl verificați de fapt ' apare doar o dată? Toți ' Căutând că există unul dintre aceste cuvinte există cel puțin o dată.
  • Acesta ar trebui să fie răspunsul acceptat. Nu este nevoie să utilizați wc -l, grep are o opțiune încorporată pentru a număra lucrurile și este chiar denumită ca fiind evidentă ca -c pentru „count”!

Răspuns

Altul soluție folosind awk și needle ca separator de câmp:

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

Dacă doriți să se potrivească cu needle urmat de punctuație, modificați separatorul de câmp în consecință, adică

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

Sau utilizați clasa: [^[:alnum:]] pentru a cuprinde toate caracterele non-alfa.

Comentarii

  • Rețineți că acest lucru necesită un awk care acceptă separatorii de câmp regexp (cum ar fi GNU awk).

Răspuns

Aceasta este soluția mea pură bash

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

Răspuns

Exemplul dvs. tipărește doar numărul de apariții pe linie și nu totalul din fișier. Dacă așa doriți, ar putea funcționa ceva de genul acesta:

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

Comentarii

  • Tu au dreptate – exemplul meu contează doar aparițiile din prima linie.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *