Unix - подсчет вхождения символа в строку/поле
Учитывая файл с такими данными (например, файл store.dat)
sid|storeNo|latitude|longitude
2tt|1|-28.0372000t0|153.42921670
9|2t|-33tt.85t09t0000|15t1.03274200
Какова команда, которая возвращает количество вхождений символа 't' в строке?
например. вернется:
count lineNum
4 1
3 2
6 3
Кроме того, чтобы сделать это по количеству вхождений по полю, какая команда возвращает следующие результаты?
например. ввод столбца 2 и символ 't'
count lineNum
1 1
0 2
1 3
например. ввод столбца 3 и символ 't'
count lineNum
2 1
1 2
4 3
Ответы
Ответ 1
Чтобы подсчитать количество символов в строке, вы можете сделать:
awk -F'|' 'BEGIN{print "count", "lineNum"}{print gsub(/t/,"") "\t" NR}' file
count lineNum
4 1
3 2
6 3
Чтобы подсчитать количество символов в поле/столбце, вы можете сделать:
столбец 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
столбец 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()
Возвращаемое значение функции - это номер подстановки. Поэтому мы используем это для печати номера.
-
NR
содержит номер строки, поэтому мы используем его для печати номера строки.
- Для печати вхождений конкретного поля мы создаем переменную
fld
и ставим номер поля, из которого мы хотим извлечь количество.
Ответ 2
grep -n -o "t" stores.dat | sort -n | uniq -c | cut -d : -f 1
дает практически точный результат, который вы хотите:
4 1
3 2
6 3
Спасибо @raghav-bhushan за подсказку grep -o
, какой полезный флаг. Флаг -n также включает номер строки.
Ответ 3
Чтобы подсчитать вхождения символа в строке:
$ awk -F 't' '{print NF-1, NR}' input.txt
4 1
3 2
6 3
это устанавливает разделитель поля к символу, который нужно подсчитать, а затем использует тот факт, что число полей больше числа разделителей.
Чтобы подсчитать вхождения в конкретном столбце cut
из этого столбца сначала:
$ 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
Ответ 4
Одно возможное решение с использованием perl
:
Содержимое 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, $.;
}
script принимает три параметра:
- Входной файл
- Char для поиска
- Столбец для поиска: если столбец является плохой цифрой, он ищет всю строку.
Запуск script без аргументов:
perl script.pl
Usage: perl script.pl input-file char [column]
С аргументами и выводами:
Здесь 0 - плохой столбец, он ищет всю строку.
perl script.pl stores.dat 't' 0
count lineNum
4 1
3 2
6 3
Здесь он ищет в столбце 1.
perl script.pl stores.dat 't' 1
count lineNum
0 1
2 2
0 3
Здесь он ищет в столбце 3.
perl script.pl stores.dat 't' 3
count lineNum
2 1
1 2
4 3
th
не является char.
perl script.pl stores.dat 'th' 3
Bad input
Ответ 5
Нет необходимости в awk или perl, только с bash и стандартными утилитами Unix:
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; }
И для конкретного столбца:
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; }
И мы можем даже избежать tr
и 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
и событие cut:
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
Ответ 6
awk '{gsub("[^t]",""); print length($0),NR;}' stores.dat
Вызов gsub() удаляет все в строке, которая не является t, а затем просто печатает длину оставшегося и текущий номер строки.
Хотите сделать это только для столбца 2?
awk 'BEGIN{FS="|"} {gsub("[^t]","",$2); print NR,length($2);}' stores.dat
Ответ 7
$ 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
Ответ 8
cat stores.dat | awk 'BEGIN {FS = "|"}; {print $1}' | awk 'BEGIN {FS = "\t"}; {print NF}'
Где $1
будет номер столбца, который вы хотите подсчитать.
Ответ 9
Вы также можете разделить строку или поле на "t" и проверить длину результирующего массива - 1. Установите для переменной col
значение 0 для строки или от 1 до 3 для столбцов:
awk -F'|' -v col=0 -v OFS=$'\t' 'BEGIN {
print "count", "lineNum"
}{
split($col, a, "t"); print length(a) - 1, NR
}
' stores.dat
Ответ 10
perl -e 'while(<>) { $count = tr/t//; print "$count ".++$x."\n"; }' stores.dat
Еще один ответ perl yay! Функция tr/t//возвращает счетчик количества раз, когда произошел перевод в этой строке, другими словами, количество раз tr найдено символ t, ++ $x поддерживает подсчет количества строк.