Перетворення таблиць .xls / .xlsx у декілька .csv на основі списку


10

Мені потрібно конвертувати всі аркуші одного .xls / .xlsx файлу в .csv. Це буде зроблено для всіх файлів .xls у всіх каталогах та підкаталогах (рекурсивно).

Крок 1. Отримайте назви аркушів усіх .xls у .csv, використовуючи:

for file in $(find . -name '*.xls' -o -name '*.xlsx');do in2csv -n "$file" > ${file%.xls}-sheetnames-list.csv; done

filename-sheetnames-list.csv може виступати як список:

sheetname1
sheetname2
sheetname3

Крок 2 : Код для перетворення конкретного аркуша в .csv за допомогою in2csv:

in2csv --sheet "SHEETNAME" filename.xls > filename-SHEETNAME.csv

Як я можу отримати кожне ім'я аркуша у .xls / x і написати кожен аркуш окремо для всіх каталогів, що містять .xls / x?

in2csv --write-sheets "-" filename.xls > filename-sheet1.csv filename-sheet2.csv .... дає вихід лише на sheet1.csv, не знаючи, як отримати з цього всі аркуші.


2
Чому б не просто findкожен .xls{,x}і петля над кожним листом, використовуючи -exec?
десерт

1
@glennjackman це ідеально на тему тут, як це було б на Unix та Linux .
тердон

Відповіді:


10

Можна просто помістити петлю всередину іншої петлі.

Щоб помилок уникнути, не використовуйте forз findрезультатами.

while IFS= read -r file; do
    while IFS= read -r sheet; do
        in2csv --sheet "$sheet" "$file" > "${file%.*}-${sheet}.csv"
    done < <(in2csv -n "$file")
done < <(find . -name '*.xls' -o -name '*.xlsx')

@muru ah crap. Ви абсолютно праві. Я перевірив себе в середовищі, де IFS вже було змінено, і, звичайно, він поширювався вниз. Ідіот . Дякуємо, редагування відмінено.
тердон

@RoVo перший варіант працює добре. Однак другий не дає мені жодних результатів чи помилок. Я не впевнений, чому; за сингл .xls in2csv --write-sheets "-" filename.xls > sheetname.csvдає лише перший аркуш. Я не знаю, яку додаткову інформацію додати, щоб написати всі аркуші. Це дасть нам підказки для виправлення вашого коду.
csheth

1
Ви оновили до версії 1.0.2? pip install csvkit -U. Я думаю, як це працює - це не те, що тобі подобається, у простого скрипту з 1-го варіанта у тебе є більше способів керувати результатами та іменами тощо.
pLumo

все ще не працює з оновленням, і так, я вважаю за краще використовувати список, ніж --write-sheets Можливо, ви можете встановити цей альтернативний варіант як іншу відповідь ... Я прийму перший варіант як відповідь тоді. Дякуємо @RoVo
csheth

1
Можливо, взагалі гарна ідея мати альтернативні варіанти в іншій відповіді. Дякую, рада, що могла допомогти.
pLumo

7

Пропуск пошуку та використання bash:

shopt -s globstar  # enable recursive globbing
for f in **/*.xls{,x}  # for files ending in .xls or .xlsx
do
    in2csv -n "$f" |   # get the sheetnames
      xargs -I {} bash -c 'in2csv --sheet "$2" "$1" > "${1%.*}"-"$2".csv' _ "$f" {} # {} will be replaced with the sheetname
done

цей сценарій виглядає елегантно, але його вихід не filename-{}.csvмістить даних. Я новачок і, здається, не можу знайти помилку, відредагувавши сценарій і прочитавши його. Дехто допомагає?
csheth

@ChintanSheth я поганий, я забув, що перенаправлення буде зовні xargs. Виправлено, не так елегантно зараз.
муру

xargsі >зло :-P. Ось чому я віддаю перевагу іншому циклу, він менш схильний до помилок.
pLumo

@RoVo Я зазвичай теж ходив на інший цикл, просто хотів тут показати інший метод.
муру

Це працює зараз, проте трохи повільніше, ніж відповідь @RoVo.
csheth

3

версія csvkit> 1.0.2 має вбудовану функцію для запису всіх аркушів:

--write-sheets: WRITE_SHEETS
                      The names of the Excel sheets to write to files, or
                      "-" to write all sheets.

Тож ви можете спробувати наступне:

find . -name '*.xls' -o -name '*.xlsx' -exec in2csv --write-sheets "-" {} \;

Примітка:

Здається, це не працює на 100%, як очікувалося. Але варто спробувати, і оскільки це перша версія з цим варіантом, можливо, у наступних версіях реалізація буде кращою / легшою.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.