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?
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".
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é.
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.
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
Cela pourrait fonctionner pour vous:
sed '/^title/!d' file | sed -n '$='