Convertissez les feuilles de calcul .xls / .xlsx en plusieurs .csv en fonction d'une liste

9

J'ai besoin de convertir toutes les feuilles d'un seul fichier .xls / .xlsx en .csv. Cela se fera sur tous les fichiers .xls dans tous les répertoires et sous-répertoires (récursivement).

Étape 1 : Obtenez les noms de feuille de tous les .xls dans un .csv en utilisant:

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

filename-sheetnames-list.csv peut agir comme une liste:

sheetname1
sheetname2
sheetname3

Étape 2 : Le code pour convertir une feuille spécifique en .csv en utilisant in2csv est:

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

Comment puis-je obtenir chaque nom de feuille dans un .xls / x et écrire chaque feuille séparément pour tous les répertoires contenant un .xls / x?

in2csv --write-sheets "-" filename.xls > filename-sheet1.csv filename-sheet2.csv .... donne une sortie uniquement sur sheet1.csv, je ne sais pas comment obtenir toutes les feuilles à partir de cela.

csheth
la source
2
Pourquoi ne pas simplement findchaque .xls{,x}et boucle sur chaque feuille à l' aide -exec?
dessert
1
@glennjackman c'est parfaitement sur le sujet ici, tout comme ce serait sur Unix & Linux .
terdon

Réponses:

10

Vous pouvez simplement mettre une boucle dans une autre boucle.

Pour éviter les erreurs, ne pas utiliser foravec les findrésultats.

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')
pLumo
la source
@muru ah merde. Vous avez absolument raison. J'avais testé dans un environnement où l'IFS avait déjà été changé donc bien sûr il se propageait vers le bas. Idiot . Merci, l'édition est revenue.
terdon
@RoVo la première option fonctionne bien. Le second cependant ne me donne aucune sortie ni erreur. Je ne sais pas pourquoi; pour un single .xls in2csv --write-sheets "-" filename.xls > sheetname.csvne donne que la première feuille. Je ne sais pas quelles informations supplémentaires ajouter pour écrire toutes les feuilles. Cela nous donnera des indices pour corriger votre code.
csheth
1
avez-vous mis à jour cette version 1.0.2? pip install csvkit -U. Je pense que la façon dont cela fonctionne n'est pas ce que vous aimez, avec le simple skript de la première option, vous avez plus de façons de contrôler la sortie et les noms de fichiers, etc.
pLumo
ne fonctionne toujours pas avec la mise à jour, et oui je préfère utiliser une liste que --write-sheets Peut-être vous pouvez définir cette option alternative comme une autre réponse ... J'accepterai alors la première option comme réponse. Merci @RoVo
csheth
1
Peut-être généralement une bonne idée d'avoir des options alternatives dans une autre réponse. Merci, heureux d'avoir pu aider.
pLumo
6

Ignorer la recherche et utiliser 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
muru
la source
ce script est élégant mais sa sortie ne filename-{}.csvcontient aucune donnée. Je suis novice et je n'arrive pas à trouver l'erreur en modifiant le script et en lisant. De l'aide?
csheth
@ChintanSheth mon mauvais, j'avais oublié que la redirection serait à l'extérieur xargs. Corrigé, pas aussi élégant maintenant.
muru
xargset >est mauvais :-P. C'est pourquoi je préfère une autre boucle, elle est moins sujette aux erreurs.
pLumo
@RoVo J'aurais généralement opté pour une autre boucle aussi, je voulais juste montrer une autre méthode ici.
muru
Cela fonctionne maintenant, mais légèrement plus lentement que la réponse @RoVo.
csheth
3

csvkit version> 1.0.2 a une fonction intégrée pour écrire toutes les feuilles:

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

Vous pouvez donc essayer ce qui suit:

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

Remarque:

Cela ne semble pas fonctionner à 100% comme prévu. Mais cela vaut la peine d'essayer et comme c'est la première version avec cette option, peut-être que dans les versions futures, la mise en œuvre est meilleure / plus facile.

pLumo
la source
0

Utilisation Gnumeric:

ssconvert -S filename.xlsx filename.csv

pour obtenir un csvfichier par feuille.

James Hirschorn
la source