Compter le nombre d'occurrences d'une chaîne en utilisant sed?

j'ai un fichier qui contient "titre" écrit en plusieurs fois. Comment puis-je trouver le nombre de fois où "title" est écrit dans ce fichier en utilisant la commande sed à condition que "title" soit la première chaîne d'une ligne? par exemple,

# title
title
title

devrait sortir le nombre = 2 parce que dans la première ligne le titre n'est pas la première chaîne.

mise à Jour

j'ai utilisé awk pour trouver le nombre total d'occurrences:

awk ' ~ /title/ {++c} END {print c}' FS=: myFile.txt
<!-Mais comment dire à awk ne compter que les lignes ayant titre la première chaîne comme expliqué dans l'exemple ci-dessus?

10
sed
demandé sur Jonathan Leffler 2009-11-23 08:56:16

6 réponses

je ne pense pas sed serait approprié, sauf si vous l'utilisez dans un pipeline pour convertir votre fichier de sorte que le mot apparaît sur des lignes distinctes, et ensuite utiliser grep -c pour compter le nombre d'occurrences.

j'aime Jonathan idée d'utiliser tr pour convertir les espaces en lignes. La beauté de cette méthode est que les espaces successifs sont convertis en lignes vides multiples mais il n'a pas d'importance parce que grep sera capable de compter juste les lignes avec le simple le mot "titre".

10
répondu pavium 2009-11-23 06:14:48

ne jamais dire Jamais. Pure sed (bien qu'il puisse nécessiter la version GNU).

#!/bin/sed -nf
# based on a script from the sed info file (info sed)
# section 4.8 Numbering Non-blank Lines (cat -b)
# modified to count lines that begin with "title"

/^title/! be

x
/^$/ s/^.*$/0/
/^9*$/ s/^/0/
s/.9*$/x&/
h
s/^.*x//
y/0123456789/1234567890/
x
s/x.*$//
G
s/\n//
h

:e

$ {x;p}

Explication:

#!/bin/sed -nf
# run sed without printing output by default (-n)
# using the following file as the sed script (-f)

/^title/! be        # if the current line doesn't begin with "title" branch to label e

x                   # swap the counter from hold space into pattern space
/^$/ s/^.*$/0/      # if pattern space is empty start the counter at zero
/^9*$/ s/^/0/       # if pattern space starts with a nine, prepend a zero
s/.9*$/x&/          # mark the position of the last digit before a sequence of nines (if any)
h                   # copy the marked counter to hold space
s/^.*x//            # delete everything before the marker
y/0123456789/1234567890/   # increment the digits that were after the mark
x                   # swap pattern space and hold space
s/x.*$//            # delete everything after the marker leaving the leading digits
G                   # append hold space to pattern space
s/\n//              # remove the newline, leaving all the digits concatenated
h                   # save the counter into hold space

:e                  # label e

$ {x;p}             # if this is the last line of input, swap in the counter and print it

voici des extraits d'une trace du script en utilisant sedsed:

$ echo -e 'title\ntitle\nfoo\ntitle\nbar\ntitle\ntitle\ntitle\ntitle\ntitle\ntitle\ntitle\ntitle' | sedsed-1.0 -d -f ./counter 
PATT:title$
HOLD:$
COMM:/^title/ !b e
COMM:x
PATT:$
HOLD:title$
COMM:/^$/ s/^.*$/0/
PATT:0$
HOLD:title$
COMM:/^9*$/ s/^/0/
PATT:0$
HOLD:title$
COMM:s/.9*$/x&/
PATT:x0$
HOLD:title$
COMM:h
PATT:x0$
HOLD:x0$
COMM:s/^.*x//
PATT:0$
HOLD:x0$
COMM:y/0123456789/1234567890/
PATT:1$
HOLD:x0$
COMM:x
PATT:x0$
HOLD:1$
COMM:s/x.*$//
PATT:$
HOLD:1$
COMM:G
PATT:\n1$
HOLD:1$
COMM:s/\n//
PATT:1$
HOLD:1$
COMM:h
PATT:1$
HOLD:1$
COMM::e
COMM:$ {
PATT:1$
HOLD:1$
PATT:title$
HOLD:1$
COMM:/^title/ !b e
COMM:x
PATT:1$
HOLD:title$
COMM:/^$/ s/^.*$/0/
PATT:1$
HOLD:title$
COMM:/^9*$/ s/^/0/
PATT:1$
HOLD:title$
COMM:s/.9*$/x&/
PATT:x1$
HOLD:title$
COMM:h
PATT:x1$
HOLD:x1$
COMM:s/^.*x//
PATT:1$
HOLD:x1$
COMM:y/0123456789/1234567890/
PATT:2$
HOLD:x1$
COMM:x
PATT:x1$
HOLD:2$
COMM:s/x.*$//
PATT:$
HOLD:2$
COMM:G
PATT:\n2$
HOLD:2$
COMM:s/\n//
PATT:2$
HOLD:2$
COMM:h
PATT:2$
HOLD:2$
COMM::e
COMM:$ {
PATT:2$
HOLD:2$
PATT:foo$
HOLD:2$
COMM:/^title/ !b e
COMM:$ {
PATT:foo$
HOLD:2$
. . .
PATT:10$
HOLD:10$
PATT:title$
HOLD:10$
COMM:/^title/ !b e
COMM:x
PATT:10$
HOLD:title$
COMM:/^$/ s/^.*$/0/
PATT:10$
HOLD:title$ 
COMM:/^9*$/ s/^/0/
PATT:10$
HOLD:title$
COMM:s/.9*$/x&/
PATT:1x0$
HOLD:title$
COMM:h
PATT:1x0$
HOLD:1x0$
COMM:s/^.*x//
PATT:0$
HOLD:1x0$
COMM:y/0123456789/1234567890/
PATT:1$
HOLD:1x0$
COMM:x
PATT:1x0$
HOLD:1$
COMM:s/x.*$//
PATT:1$
HOLD:1$
COMM:G
PATT:1\n1$
HOLD:1$
COMM:s/\n//
PATT:11$
HOLD:1$
COMM:h
PATT:11$
HOLD:11$
COMM::e
COMM:$ {
COMM:x
PATT:11$
HOLD:11$
COMM:p
11
PATT:11$
HOLD:11$
COMM:}
PATT:11$
HOLD:11$

l'ellipse représente les lignes de sortie que j'ai omises ici. La ligne avec "11" sur elle par elle-même est où le compte final est produit. C'est la seule sortie que vous obtiendriez quand le sedsed débogueur n'est pas utilisé.

12
répondu Dennis Williamson 2017-12-07 18:58:59

réponse révisée

En résumé, vous ne pouvez pas-sed n'est pas l'outil adéquat pour le travail (il ne peut pas compter).

sed -n '/^title/p' file | grep -c

cherche les lignes de titre de départ et les imprime, alimentant la sortie dans grep pour les Compter. Ou, de manière équivalente:

grep -c '^title' file

réponse originale-avant que la question ne soit modifiée

En résumé, vous ne pouvez pas - ce n'est pas l'outil approprié pour le travail.

grep -c title file

sed -n /title/p file | wc -l

la seconde utilise sed comme substitut pour grep et envoie la sortie de 'wc' pour compter les lignes. Les deux comptent le nombre de lignes contenant le "titre", plutôt que le nombre d'occurrences du titre. Vous pouvais résoudre ce problème avec quelque chose comme:

cat file |
tr ' ' '\n' |
grep -c title

la commande' tr ' convertit les blancs en nouvelles lignes, mettant ainsi chaque mot séparé de l'espace sur sa propre ligne, et donc grep ne peut compter que les lignes contenant le titre du mot. Cela fonctionne à moins que vous n'ayez des séquences telles que "titre-entitlement" où il n'y a pas d'espace séparant les deux occurrences du titre.

8
répondu Jonathan Leffler 2009-11-23 06:05:10

juste une gawk commande. N'utilisez pas grep-c parce qu'il ne compte ligne avec "titre" dans elle, indépendamment de combien "titre"il y a dans la ligne.

$ more file
#         title
#  title
one
two
#title
title title
three
title junk title
title
four
fivetitlesixtitle
last

$ awk '!/^#.*title/{m=gsub("title","");total+=m}END{print "total: "total}' file
total: 7

si vous voulez juste "title" comme première chaîne, utilisez "= = " au lieu de ~

awk ' == "title"{++c}END{print c}' file
3
répondu ghostdog74 2009-11-23 06:23:26
sed 's/title/title\n/g' file | grep -c title
3
répondu ghostdog74 2009-11-23 10:55:03

Cela pourrait fonctionner pour vous:

sed '/^title/!d' file | sed -n '$='
2
répondu potong 2011-12-13 00:45:51