Как стать автором
Обновить

Конвертируем .xlsx в .csv в bash с zenity

Уровень сложностиПростой
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-выражение, клеющее ; в конце строки.

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.