É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
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
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. fld
et plaçons le numéro du champ que nous souhaitons extraire des comptes. 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.
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
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:
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
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 cat
s:
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
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
$ 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
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.
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
cat stores.dat | awk 'BEGIN {FS = "|"}; {print $1}' | awk 'BEGIN {FS = "\t"}; {print NF}'
Où $1
serait un numéro de colonne que vous souhaitez compter.