Считать по первому столбцу, считать отдельно по второму столбцу и выводить группы по первому столбцу?

Предполагая, что в каталоге верхнего уровня нет файлов:

for i in *; do (cd "$i"; rm -rf *); done

или

for i in *; do (cd "$i"; for j in *; do rm -rf "$j"; done); done

Я предпочитаю последний вариант, потому что он не пытается удалить *, если каталог пуст, и его можно легко модифицировать, чтобы включить только некоторые шаблоны файлов. Для чего-то более сложного используйте find.

4
27.10.2018, 18:14
4 ответа

Чтобы получить первые два столбца вывода:

$ cut -d, -f1 <file | sort | uniq -c | awk -vOFS=, '{ print $2, $1 }'
A,3
B,2
C,2
D,1

Это извлекает первый столбец исходного файла, сортирует его и подсчитывает количество повторяющихся записей. awkв конце просто меняет местами столбцы и вставляет запятую в -между ними.

Последний столбец может быть с

$ sort -u <file | cut -d, -f1 | uniq -c | awk -vOFS=, '{ print $1 }'
2
2
1
1

Это сортирует исходные данные и отбрасывает дубликаты. Затем извлекается первый столбец и подсчитывается количество дубликатов , что . awkв конце извлекает только счетчики.

Комбинируя их с помощью bashиpaste:

$ paste -d, <( cut -d, -f1 <file | sort    | uniq -c | awk -vOFS=, '{ print $2, $1 }' ) \
            <( sort -u <file | cut -d, -f1 | uniq -c | awk -vOFS=, '{ print $1 }' )
A,3,2
B,2,2
C,2,1
D,1,1

Если вы предварительно -отсортируете данные, это может быть немного сокращено (и значительно ускорено):

$ sort -o file file

$ paste -d, <( cut -d, -f1 <file        | uniq -c | awk -vOFS=, '{ print $2, $1 }' ) \
            <( uniq <file | cut -d, -f1 | uniq -c | awk -vOFS=, '{ print $1 }' )
A,3,2
B,2,2
C,2,1
D,1,1
2
27.01.2020, 20:53

Я хотел посмотреть, можно ли решить эту проблему с помощью лайнера Perl one -, что мне удалось выяснить:

$ perl -F, -ane '$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++; \
    END { print "$_, $lcnt{$_}, ". (keys %{ $ccnt{$_} }). "\n" for sort keys %lcnt }' \
      file
A, 3, 2
B, 2, 2
C, 2, 1
D, 1, 1

Разбивка

перебор файла

Этот -вкладыш может показаться очень сложным, но на самом деле он довольно прост, если разобрать его. В основе лежит этот механизм в Perl:

$ perl -F, -ane '...; END {... }' file

Это говорит Perl взять файл fileи перебрать его в цикле, а затем автоматически -разделить его, используя -F,в качестве символа-разделителя, после завершения выполнить блок END {..}один раз и выйти.

Например:

$ perl -F, -ane 'print "arg1: $F[0] arg2: $F[1]"; END { print "DONE\n" }' file
arg1: A arg2:  10
arg1: B arg2:  11
arg1: C arg2:  12
arg1: A arg2:  10
arg1: B arg2:  12
arg1: D arg2:  10
arg1: A arg2:  12
arg1: C arg2:  12
DONE

ПРИМЕЧАНИЕ.:Функция Perl auto -split автоматически помещает столбцы в массив @F, здесь я использую элементы 1 и 2, $F[0]и $F[1].

Подсчет вещей

Следующее, что нам нужно сделать, это подсчитать различные биты ввода. Для этого мы воспользуемся мощью хэшей в Perl. Мы будем использовать 2, %lcntи %ccnt.

ПРИМЕЧАНИЕ.:Одной из наиболее раздражающих вещей в Perl является переключение нотации при определении хэша и при доступе к нему. При доступе к нему мы переключаемся с %lcntна $lcnt["A"], но я отвлекся.

$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++;
  • %lcnt-количество символов из 1-го столбца
  • %ccnt-Двухмерный хэш, содержащий 2 координаты, для доступа к подсчету 2-го столбца

ПРИМЕЧАНИЕ.:Такой подсчет позволяет выполнять уникальную функцию просто за счет того, как мы подсчитываем биты.

Например, рассмотрим содержимое хэша %lcnt:

$ perl -F, -ane '$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++; \
    END { print "key: $_\n" for sort keys %lcnt }' file
key: A
key: B
key: C
key: D

Если мы хотим увидеть значение для каждого хэша:

$ perl -F, -ane '$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++; \
    END { print "key: $_ val: $lcnt{$_}\n" for sort keys %lcnt }' file
key: A val: 3
key: B val: 2
key: C val: 2
key: D val: 1

ПРИМЕЧАНИЕ.:Здесь мы видим, что $lcnt{$F[0]}++проделал всю тяжелую работу по подсчету каждого символа, когда мы прошлись по файлу и добавили их в хэш %lcnt.

Это КОНЕЦ

Последняя часть головоломки состоит в том, чтобы отобразить всю эту собранную информацию удобным способом.Для этого мы будем использовать это вEND {...}:

print "$_, $lcnt{$_}, ". (keys %{ $ccnt{$_} }). "\n" for sort keys %lcnt

Это перебирает список ключей из %lcntи печатает следующую строку:

$_, $lcnt{$_}, ". (keys %{ $ccnt{$_} }). "\n"

Если вам сложно увидеть вышеприведенную структуру, вот она в более общем виде:

A, 3, 2
      ^--- (keys %{ $ccnt{$_} })  ## count of unique columns for each character ($_)
   ^------ $lcnt{$_}              ## count of each character
^--------- $_                     ## character

Это создаст строку, содержащую символ ($_), значение счетчика для этого символа ($lcnt{$_}), а затем количество уникальных значений из 2-го столбца для каждого символа.

Ссылки

1
27.01.2020, 20:53
datamash -t, -s -g 1 count 1 countunique 2 < input.txt

Вход

A, 10
B, 11
C, 12
A, 10
B, 12
D, 10
A, 12
C, 12

Выход

A,3,2
B,2,2
C,2,1
D,1,1
0
27.01.2020, 20:53

С помощью небольшого sqlite3скрипта, запускаемого из командной строки, где input.csv— ваши входные данные:

sqlite3 -batch <<EOF
.mode csv

CREATE TABLE data (letter TEXT, number INTEGER);

.import input.csv data

SELECT letter, COUNT(*) AS lcount, COUNT(DISTINCT number) AS dcount
FROM data
GROUP BY letter ;
EOF

Это работает так

$ bash query.sqlite 
A,3,2
B,2,2
C,2,1
D,1,1
2
27.01.2020, 20:53

Теги

Похожие вопросы