Мне нравятся оба ответа (SQL, AWK ), потому что они являются стандартными языками и реализуют алгоритм идиоматически. Я собирался еще больше понизить вопрос, потому что он, кажется, настаивает на конкретном решении.
Но именно в этом проблема fgdark :вы слишком полагаетесь на утилиты и не понимаете (алгоритма ).
How could I pipe together cut, grep, numaverage in this manor (other commands may help such as cat, uniq, wc)?
Вы можете «легко» найти конвейерное решение, начав с временных файлов, а когда цепочка заработает, вы объедините их вместе. Результат будет неудовлетворительным. У меня нет numaverage, для начала. Производительность также.
Здесь необходим какой-то «настоящий» язык программирования, например SQL или AWK. Или perl, или python, или C. Или bash -, но bash как скриптовый язык с ассоциативными массивами и арифметическими операторами , а не bash "только" как оболочка.
Вам не нужна усредненная()функция , как в случае решения SQL, вы можете просто считать, складывать и делить данные, которые вы прочитали, в свои массивы.
Поэтому, если вы хотите создавать дополнительные отчеты по данным, вам следует выбрать язык . SQL немного особенный, он хорошо подходит для анализа данных . Другие упомянутые (awk, perl, python, C, даже bash )сильны в данных обработке(манипулировании переменными/массивами/структурами ). Но есть большое совпадение.
Несколько лет я работал с SQL; так я бы сохранил запрос и его вызов:
SQL='select a as Name, count(*) as Count, avg(b) as Average'
SQL+=' from file'
SQL+=' group by a'
csvsql -tSH --query $SQL file | csvformat -T
'Это не критика, а попытка проиллюстрировать, как структурирован-язык структурированных запросов . Это хрестоматийная демонстрация предложения group by
с агрегатными функциями count
и avg
.
Bash предоставляет синтаксис +=
, позволяющий легко это сделать.
Вы должны выполнить целочисленное деление, чтобы получить значение параметра -l
в split
. Оболочка отлично подходит для целочисленных делений:
lines_number=$(wc -l < file)
split -l $((lines_number / 10)) file
wc -l x*
907 xaa
907 xab
907 xac
907 xad
907 xae
907 xaf
907 xag
907 xah
907 xai
907 xaj
4 xak
9074 total
Если вы хотите использовать для этого awk
, вы должны напечатать целое число:
wc -l file | awk '{print int($1/10)}'
907
И вам придется соединить последние два файла. Предполагая, что вы выводите их все в один и тот же пустой каталог, вы можете сделать:
printf "%s\n" x* | tail -n2 | xargs cat > last_file
wc -l < last_file
911
В приведенном выше примере мы знаем, что сопоставление универсальных объектов будет извлекать новые файлы в алфавитном порядке, и мы знаем, что разделение именует выходные файлы в этом порядке.
Примечание :Также я предпочитаю использовать собственный префикс и числовую индексацию для выходных файлов split
, например:
split -d -l 907 file new_file
Примечание. :Поскольку длина суффикса по умолчанию равна 2, (см. man split
и-a
)split
будут называть файлы как new_file00
, new_file01
, которые снова сортируются в алфавитном порядке, если они меньше 100 (Длина суффикса из 3 цифр ). Другим вариантом одновременного использования цифровых суффиксов (для удобочитаемости )и алфавитного порядка является установка длины суффикса -a
на соответствующее значение.
Чтобы включить весь процесс в небольшой сценарий, вы можете сделать это. Я также добавил проверку, если модуль равен нулю, в этом случае мы не изменяем никакие выходные файлы.
#!/bin/bash
f="file"
prefix="new_file"
lines_number=$(wc -l < "$f")
split -d -l $((lines_number / 10)) "$f" "$prefix"
if ((lines_number % 10 != 0)); then
last_file=$(printf "%s\n" "$prefix"* | tail -1)
pre_last_file=$(printf "%s\n" "$prefix"* | tail -2 | head -1)
cat "$last_file" >> "$pre_last_file" && rm -- "$last_file"
fi