LinuxForum.Fans
Тема

Bash работа с таблицами

Автор: faddist88 14 сообщений 1241 просмотров
25.04.2022 14:19 #437491

Как обработать таблицу в bash?

Есть команда которая генерирует таблицу из трех колонок Status, Owner, Value. В столбце Status - текстовые значения, в стоблце Owner - текстовое значение может быть с пробелом, в колонке value - целочисленные, но могут быть пустые (вместо 0). Например:
#gentbl
Status Owner Value
active Alpha A. 101
active Betta 5
active Alpha A.
error Alpha A. 2
active Betta 359

Требуется подсчитать сумму значений по каждому владельцу в статусе active.

Пробовал разбирать по строкам через цикл for, но разбор идет не по строкам, а словам, причем из-за особенностей стоблбцов Owner и Value способ очень сложен.
for line in $(gentbl)
do
...
done

Заранее спасибо

25.04.2022 16:47 #437492

faddist88, реализация на bash критична? Если нет, пробуйте Python + библиотеку Numpy.

25.04.2022 16:50 #437493

Очень желательно именно на bash, т.к. решение типовое, а python'a может не быть

26.04.2022 05:30 #437494
"faddist88" написал:
Очень желательно именно на bash, т.к. решение типовое, а python'a может не быть

bash не совсем для этого предназначен.
т.е. в нём нет встроенных средств для генерации таблиц.
напишите утилиту, на вашем любимом языке программирования.

26.04.2022 10:00 #437497
ValentinK написал:
[quote="faddist88"]Очень желательно именно на bash, т.к. решение типовое, а python'a может не быть

bash не совсем для этого предназначен.
т.е. в нём нет встроенных средств для генерации таблиц.
напишите утилиту, на вашем любимом языке программирования.[/quote]
Понятно что bash не очень подходит - день гугления до создания темы мне это подсказало, но очень хочется реализовать именно на bash, чтобы работало всегда вне зависимости от установленных библиотек и т.д. Понимаю что это попытка совершуть кругосветное путешествие на мопеде: очень сложно, но в целом можно. Только подскажите как выделять в переменную целую строку из вывода. Как разбирать строку мне уже более менее понятно.

26.04.2022 10:20 #437498
"faddist88" написал:
чтобы работало всегда вне зависимости от установленных библиотек

Вариант с компиляцией в двоичный код не подходит?

26.04.2022 10:30 #437499
"faddist88" написал:
как выделять в переменную целую строку из вывода

написать парсер.
искать символ CR во вводе.
или использовать функцию языка типа как cin >> a или readln(a);

26.04.2022 10:34 #437500
Rizado написал:
[quote="faddist88"]чтобы работало всегда вне зависимости от установленных библиотек

Вариант с компиляцией в двоичный код не подходит?[/quote]
Можно ссылку с примером чтобы было понятно как это сделать. Это можно будет потом таскать между серверами на разных ОС и железе?
Добавлено: 26.04.2022 10:34:40

ValentinK написал:
[quote="faddist88"] как выделять в переменную целую строку из вывода

написать парсер.
искать символ CR во вводе.
или использовать функцию языка типа как cin >> a или readln(a);[/quote]
Опять же можно пример или ссылку

26.04.2022 10:44 #437501
"faddist88" написал:
Опять же можно пример или ссылку

создать массив строк
ввести текст
в цикле пока не закончится строка
искать разделитель строки
добавить строку в массив строк
дальше

26.04.2022 11:35 #437502
ValentinK написал:
[quote="faddist88"]Опять же можно пример или ссылку

создать массив строк
ввести текст
в цикле пока не закончится строка
искать разделитель строки
добавить строку в массив строк
дальше[/quote]


Алгоритм понятен. Я даже пробовал конструкции типа
for line in $(gentbl)
do
парсим строку $line
done

Но в этом случае в $line записываются не строки целиком, а слова или символы разделенные пробелами.

Если использовать такую конструкцию
result=$(gentbl)
То в каждой строке своя ячейка, но там где ячейки пустые там нет пустой строки
Добавлено: 26.04.2022 11:35:59

Как распарсить строку я более-менее понимаю. Проблема именно в способе перебора строк вывода результата

26.04.2022 16:11 #437503
"faddist88" написал:
Можно ссылку с примером чтобы было понятно как это сделать. Это можно будет потом таскать между серверами на разных ОС и железе?

От железа зависеть практически не будет, а вот под Linux/Windows надо будет отдельно компилировать.
А ссылку - вопрос слишком абстрактный, записит от того, на каком языке писать.

26.04.2022 19:38 #437504
"faddist88" написал:
for line in $(gentbl)
do
парсим строку $line
done

Но в этом случае в $line записываются не строки целиком, а слова или символы разделенные пробелами.

парсить в цикле по строкам по разделителю CR
парсить в цикле по строкам по разделителю пробелу
обрабатывать табличное значение
дальше
дальше

27.04.2022 12:05 #437505
"faddist88" написал:
Как обработать таблицу в bash?

Здравствуйте. В каждой таблице, если это именно таблица, а не набор строк, должен присутствовать разделитель полей/столбцов. Если его нет - значит это обычный текст, который так же бесполезно разбивать на столбцы/поля, как искать иголку в стоге сена. Если нет разделителя - мы читаем обычную страницу из любой книги и неважно, что соседние ячейки соответствуют определённому формату: содержит она пробел или не содержит, стоит там точка или не стоит, похожа она на ту, что сверху/снизу или нет. Без разделителя вся эта писанина, называемая таблицей - обычный набор текста, который ничем не структурирован.

Предположим, что Ваша программа gentbl всё же сгенерировала Вашу таблицу как таблицу и разделителем полей является табуляция (TAB). Тогда Ваша задача может быть решена старым дедовским способом, например через промежуточные файлы (их будет не менее 4-х):

Скрипт ./start.sh

text

#!/bin/bash

#Если разделитель полей - табуляция, то...

#Нормализация исходной таблицы ./table: убираем заголовок, заменяем все пробелы на '_', #выделяем статус 'active' и сохраняем всё это добро в файл ./table_normalized cat ./table | tr ' ' '_' | tail -n+2 | grep 'active' > ./table_normalized

#Список уникальных имён сохраняем в файл ./owners cat ./table_normalized | cut -f2 | sort | uniq > ./owners

#Сохраняем список сумм для каждого пользователя в файлы ./sum_ИмяПользователя while read p; do cat table_normalized | grep "$p" | cut -f3 | grep -v '_' > "sum_$p" done < ./owners

#Подсчет суммы для каждого owner-а из их собственных файлов ./sum_ИмяПользователя for i in $(ls ./sum_*); do #Обнуляем счётчик сумм result=0

while read p; do let result=result+"$p" done < $i

echo "Сумма для $(echo $i | cut -c 7-): $result" done

read -p "Enter - выйти..."

Результат работы:

text

> ./start.sh
Сумма для Alpha_A.: 101
Сумма для Betta: 364
Enter - выйти...

Скачать рабочий пример с нормальной таблицей...

27.04.2022 13:44 #437506

alex_q_2000, да тут проще можно сделать.
1. Считываем строку.
2. Если первые 6 символов образуют слово "active" (для надёжности приведём к нижнему регистру), переходим к шагу 3, иначе возврат на шаг 1.
3. Считываем из конца строки по одному символу, если это цифры. Если нет - имеем ноль. Прибавляем полученное значение к сумме.
4. Пока не достигнут конец файла, переход к шагу 1.

Кстати, цифры в конце строки можно вырезать регулярным выражением: /(\d*)$/gi, дальше пусть автор темы сам подумает. Если в конце цифр нет, это выражение вернёт пустую строку.

Ну или сразу для полного анализа строки: /active .+ (\d*)$/gi (обратите внимание на пробелы в выражении, они там нужны!).

Войдите или зарегистрируйтесь, чтобы ответить.