web-dev-qa-db-fra.com

Compter les occurrences de caractère par ligne/champ sous Unix

Étant donné un fichier avec des données comme celle-ci (c.-à-d. Fichier stores.dat)

sid|storeNo|latitude|longitude
2tt|1|-28.0372000t0|153.42921670
9|2t|-33tt.85t09t0000|15t1.03274200

Quelle est la commande qui renverrait le nombre d'occurrences du caractère 't' par ligne?

par exemple. retournerais:

count   lineNum
   4       1
   3       2
   6       3

Aussi, pour le faire par nombre d'occurrences par champ, quelle est la commande pour renvoyer les résultats suivants? 

par exemple. entrée de la colonne 2 et du caractère 't'

count   lineNum
   1       1
   0       2
   1       3

par exemple. entrée de la colonne 3 et du caractère 't'

count   lineNum
   2       1
   1       2
   4       3
39
toop

Pour compter l'occurrence d'un caractère par ligne, vous pouvez faire: 

awk -F'|' 'BEGIN{print "count", "lineNum"}{print gsub(/t/,"") "\t" NR}' file
count lineNum
4       1
3       2
6       3

Pour compter l'occurrence d'un caractère par champ/colonne, vous pouvez faire: 

colonne 2:

awk -F'|' -v fld=2 'BEGIN{print "count", "lineNum"}{print gsub(/t/,"",$fld) "\t" NR}' file
count lineNum
1       1
0       2
1       3

colonne 3:

awk -F'|' -v fld=3 'BEGIN{print "count", "lineNum"}{print gsub(/t/,"",$fld) "\t" NR}' file
count lineNum
2       1
1       2
4       3
  • La valeur de retour de la fonction gsub() est le nombre de substitutions effectuées. Nous utilisons donc cela pour imprimer le numéro. 
  • NR contient le numéro de ligne afin que nous l'utilisions pour imprimer le numéro de ligne. 
  • Pour imprimer les occurrences d'un champ particulier, nous créons une variable fld et plaçons le numéro du champ que nous souhaitons extraire des comptes. 
43
jaypal singh
grep -n -o "t" stores.dat | sort -n | uniq -c | cut -d : -f 1

donne presque exactement le résultat souhaité:

  4 1
  3 2
  6 3

Merci à @ raghav-bhushan pour l'indice grep -o, quel indicateur utile. Le drapeau -n inclut également le numéro de ligne.

36
Gabriel Burt

Pour compter les occurrences d'un caractère par ligne:

$ awk -F 't' '{print NF-1, NR}'  input.txt
4 1
3 2
6 3

ceci définit le séparateur de champ sur le caractère à compter, puis utilise le fait que le nombre de champs est supérieur à un nombre de séparateurs.

Pour compter les occurrences dans une colonne particulière cut de cette colonne en premier:

$ cut -d '|' -f 2 input.txt | awk -F 't' '{print NF-1, NR}'
1 1
0 2
1 3

$ cut -d '|' -f 3 input.txt | awk -F 't' '{print NF-1, NR}'
2 1
1 2
4 3
12
artm

Une solution possible en utilisant Perl:

Contenu de script.pl :

use warnings;
use strict;

## Check arguments:
## 1.- Input file
## 2.- Char to search.
## 3.- (Optional) field to search. If blank, zero or bigger than number
##     of columns, default to search char in all the line.
(@ARGV == 2 || @ARGV == 3) or die qq(Usage: Perl $0 input-file char [column]\n);

my ($char,$column);

## Get values or arguments.
if ( @ARGV == 3 ) {
        ($char, $column) = splice @ARGV, -2;
} else {
        $char = pop @ARGV;
        $column = 0;
}

## Check that $char must be a non-white space character and $column 
## only accept numbers.
die qq[Bad input\n] if $char !~ m/^\S$/ or $column !~ m/^\d+$/; 

print qq[count\tlineNum\n];

while ( <> ) {
        ## Remove last '\n'
        chomp;

        ## Get fields.
        my @f = split /\|/;

        ## If column is a valid one, select it to the search.
        if ( $column > 0 and $column <= scalar @f ) {
                $_ = $f[ $column - 1];
        }

        ## Count.
        my $count = eval qq[tr/$char/$char/];

        ## Print result.
        printf qq[%d\t%d\n], $count, $.;
}

Le script accepte trois paramètres:

  1. Fichier d'entrée
  2. Char à rechercher
  3. Colonne à rechercher: Si column est un mauvais chiffre, il recherche toute la ligne.

Exécuter le script sans arguments:

Perl script.pl
Usage: Perl script.pl input-file char [column]

Avec des arguments et sa sortie:

Ici 0 est une mauvaise colonne, elle recherche toute la ligne.

Perl script.pl stores.dat 't' 0
count   lineNum
4       1
3       2
6       3

Ici, il cherche dans la colonne 1.

Perl script.pl stores.dat 't' 1
count   lineNum
0       1
2       2
0       3

Ici, il cherche dans la colonne 3.

Perl script.pl stores.dat 't' 3
count   lineNum
2       1
1       2
4       3

th n'est pas un caractère.

Perl script.pl stores.dat 'th' 3
Bad input
3
Birei

Pas besoin de awk ou de Perl, seulement avec les utilitaires Unh bash et standard:

cat file | tr -c -d "t\n" | cat -n |
  { echo "count   lineNum"
    while read num data; do
      test ${#data} -gt 0 && printf "%4d   %5d\n" ${#data} $num
    done; }

Et pour une colonne particulière:

cut -d "|" -f 2 file | tr -c -d "t\n" | cat -n |
  { echo -e "count lineNum"
    while read num data; do
      test ${#data} -gt 0 && printf "%4d   %5d\n" ${#data} $num
    done; }

Et nous pouvons même éviter tr et les cats:

echo "count   lineNum"
num=1
while read data; do
  new_data=${data//t/}
  count=$((${#data}-${#new_data}))
  test $count -gt 0 && printf "%4d   %5d\n" $count $num
  num=$(($num+1))
done < file

et event la coupe:

echo "count   lineNum"
num=1; OLF_IFS=$IFS; IFS="|"
while read -a array_data; do
  data=${array_data[1]}
  new_data=${data//t/}
  count=$((${#data}-${#new_data}))
  test $count -gt 0 && printf "%4d   %5d\n" $count $num
  num=$(($num+1))
done < file
IFS=$OLF_IFS
2
jfg956
awk '{gsub("[^t]",""); print length($0),NR;}' stores.dat

L'appel à gsub () supprime tout ce qui n'est pas t dans la ligne, puis affiche simplement la longueur de ce qui reste et le numéro de la ligne en cours.

Voulez-vous le faire juste pour la colonne 2?

awk 'BEGIN{FS="|"} {gsub("[^t]","",$2); print NR,length($2);}' stores.dat
2
vulcan
 $ cat -n test.txt
 1  test 1
 2  you want
 3  void
 4  you don't want
 5  ttttttttttt
 6  t t t t t t

 $ awk '{n=split($0,c,"t")-1;if (n!=0) print n,NR}' test.txt
 2 1
 1 2
 2 4
 11 5
 6 6
1
Haven Holmes
Perl -e 'while(<>) { $count = tr/t//; print "$count ".++$x."\n"; }' stores.dat

Une autre réponse de Perl, oui! La fonction tr/t // renvoie le nombre de fois où la traduction a eu lieu sur cette ligne, autrement dit le nombre de fois tr a trouvé le caractère ' t '. ++ $ x maintient le nombre de lignes. 

0
Steve Thorn

Vous pouvez également scinder la ligne ou le champ avec "t" et vérifier la longueur du tableau résultant - 1. Définissez la variable col sur 0 pour la ligne ou entre 1 et 3 pour les colonnes:

awk -F'|' -v col=0 -v OFS=$'\t' 'BEGIN {
    print "count", "lineNum"
}{
    split($col, a, "t"); print length(a) - 1, NR
}
' stores.dat
0
Cole Tierney
cat stores.dat | awk 'BEGIN {FS = "|"}; {print $1}' |  awk 'BEGIN {FS = "\t"}; {print NF}'

$1 serait un numéro de colonne que vous souhaitez compter.

0
Jelena