
Fjodor
Linux-энтузиаст, романтизирую SRE и DevNet!
В распоряжении есть .xlsx
-файл. Мне надо извлечь все строки из столбца, и преобразовать входные данные в комплектацию из одной строки, разделенных точкой с запятой.
Сценарий с ssconvert
ssconvert
— продукт из состава набора инструментов Gnumeric
, предназначенная для конвертации электронных таблиц между различными форматами, такими как xls
, xlsx
, csv
и другими. Он поддерживает как чтение, так и запись в различных форматах. Продукт легковесный, высокопроизводительный даже при объемных данных. Работает из командной строки, чтобы позволяет интегрировать его в сценарии, автоматизируя процесс конвертации.
Исходный код
#!/usr/bin/env bash
function convert {
declare xlsx="${*}";
declare -a csv=($(ssconvert --export-type=Gnumeric_Excel:xlsx "${xlsx}" --export-type=Gnumeric_stf:stf_csv fd://1));
declare -i length=${#csv[@]};
declare -g string="";
declare -i i=0;
for((i=0; i<${length}; i++)); do
[[ ${i} -eq $((length-1)) ]] && \
string+="${csv[${i}]}" || \
string+="${csv[${i}]};";
done;
};
function main {
if command -v gnumeric zenity &> /dev/null; then
convert "$(zenity --file-selection --title='Выберите XLSX-файл')" && \
zenity --info --text="${string:-Пустой вывод\!}" --title="Отформатированный результат";
else
exit 127;
fi;
};
# Спусковой крючок
main;
Было острое желание интегрировать этот сценарий с визуализирующим компонентом типа zenity
. В бизнес-логике main
прежде всего проверяем систему на наличие gnumeric
с zenity
, оглушая шум (заметка моего знакомого SRE-инженера, который объясняет различие между command -v и which):
function main {
if command -v gnumeric zenity &> /dev/null; then ...
Я предпочитаю функции объявлять с помощью, насколько мне известно, устаревшего ключевого слова function
— это позволяет облегчить рекурсивную фильтрацию сценариев, выделив только функции, e. g.: grep -r "function" ...
, только, следует учесть, что это нарушает совместимость со стандартом POSIX. Здесь, спусковым крючком выступает функция main
, который всегда можно парализировать закомментировав её вызов.
declare -a csv=($(ssconvert --export-type=Gnumeric_Excel:xlsx "${xlsx}" --export-type=Gnumeric_stf:stf_csv fd://1));
Здесь мы инициализируем переменную csv как индексируемый массив. Используя ssconvert
опцией --export-type
мы вручную указываем соответствующий тип экспорта Gnumeric_Excel:xlsx
, на вход .xlsx
-файл, а для .csv
тип экспорта — Gnumeric_stf:stf_csv
. На выход вместо имя файла, я ввожу адрес выходного потока данных (aka stdout) fd://1
, чтобы значения построчно присвоить массиву.
for((i=0; i<${length}; i++)); do
[[ ${i} -eq $((length-1)) ]] && \
string+="${csv[${i}]}" || \
string+="${csv[${i}]};";
done;
Условная бизнес-логика, в которой мы начинаем строить однострочный результат обработки данных. В заранее проинициализированной целочисленной переменной length
, которая хранит в себе размер массива, (с точки зрения оптимизации, при декларации типа declare -i
сокращается объемный накладной расход ресурсов преобразования из строку в целое число в 20 раз! Подобный эксперимент можно провести самому, исследуя с time
), мы проверяем на последний элемент массива; если элемент последний, выполняется else if
-выражение, клеющее ;
в конце строки.