3

I am trying figure out how to save a specific Excel sheet as CSV via command line on Linux. I am able to save the first sheet with the command below:

libreoffice --headless --convert-to csv --outdir /tmp /tmp/test.xls

It seems that there should be a way to specify the sheet I want to save, but I am not able to find one.

Is there a way to save it via LibreOffice?

Community
  • 1
  • 1
Andrey
  • 1,808
  • 1
  • 16
  • 28
  • Hi Andrey Slight change since I mis read your orginal question. Hope this helps –  Jul 13 '19 at 18:14

3 Answers3

3

I know OP has probably moved on by now but since this was the first result in my search, I figured I'd take a stab at leaving an answer that works and is actually usable for the next googler.

First, LibreOffice still only lets you save the first sheet. If that is all you need, then try libreoffice --convert-to csv Test.ods. Interestingly, the GUI does the same thing - only letting you export the active sheet. So it's not that terminal is ignored so much that it is just a limitation in LibreOffice.

I needed to extract several sheets into separate csv files so "active sheet only" didn't cut it for me. After seeing this answer only had a macro as the suggestion, I kept looking. There were a few ways to get the other sheets in various places I found after this page. I don't recall any of them that allowed you to extract a specific sheet (unless it was some random github tool that I skipped over).

I liked the method of using the Gnumeric spreadsheet application because it is in most central repos and doesn't involve converting to xsl / xslx first. However, there are a few caveats to be aware of.

First, if you want to be able to extract only one sheet without knowing the sheet name ahead of time then this won't work. If you do know the sheet name ahead or time or are ok with extracting all the sheets, then this works fairly well. The sheet name can be used to create the output files so it's not completely lost which is nice too.

Second, if you want the quoting style to match the same style you'd get by manually exporting from the LibreOffice GUI, then you will need to forget the term "csv" and think in terms of "txt" until you finish the conversion (e.g. convert to .txt files then rename them). Otherwise, if you don't care about an exact match on quoting style, then this doesn't matter. I will show both ways below. If you don't know what a quoting style is, basically in csv if you have spaces or a string that contains , you put quotes around the cell value to distinguish from the commas used to separate text. Some programs quote everything, others quote if there are spaces and/or commas in the value, and others don't quote at all (or only quote for commas?).

Last, there seems to be a difference in the precision when converting via LibreOffice and Gnumeric's ssconvert tool. Not enough to matter for most people, for most use-cases. But still worth noting. In my original ods file, I had a formula that was taking the average of 3 cells with 58.14, 59.1, and 59.05 respectfully. This average came to 58.7633333333333 when I exported via the LibreOffice GUI. With ssconvert, the same value was 58.76333333333333 (e.g. it had one additional decimal place compared to LibreOffice version). I didn't really care for my purposes but if you need to exactly match LibreOffice or don't want the extra precision, then I guess it might matter.

From man ssconvert, we have the following options:

  • -S, --export-file-per-sheet: Export a file for each sheet if the exporter only supports one sheet at a time. The output filename is treated as a template in which sheet number is substituted for %n, sheet name is substituted for %s, and sheet object name is substituted for %o in case of graph export. If there are no substitutions, a default of ".%n" is added.

  • -O, --export-options=optionsstring : Specify parameters for the chosen exporter. optionsstring is a list of parameter=value pairs, separated by spaces. The parameter names and values allowed are specific to the exporter and are documented below. Multiple parameters can be specified

During my testing, the -O options were ignored if I specified the output file with a .csv extension. But if I used .txt then they worked fine. I'm not covering them all and I'm paraphrasing so read the man page if you want more details. But some of the options you can provide in the optionsstring are as follows:

  • sheet: Name of the sheet. You can repeat this option for multiple sheets. In my testing, using indexes did NOT work.

  • separator: If you want a true comma separated values files, then we'll need to use commas.

  • format: I'll be using raw bc I want the unformatted values. If you need something special for dates, etc read the man page.

  • quoting-mode: when to quote values. can be always, auto, or never. If you want to mimic LibreOffice as closely as possible, choose never.

So let's get to a terminal.

# install gnomic on fedora
$ sudo dnf install -y gnumeric
 
# install gnomic on ubuntu/mint/debian
$ sudo apt-get install -y gnumeric

# use the ssconvert util from gnumeric to do the conversion
# let it do the default quoting - this will NOT match LibreOffice
# in this example, I am just exporting 1 named sheet using
#   -S, --export-file-per-sheet
$ ssconvert -S -O 'sheet=mysheet2' Test.ods test_a_%s.csv
$ ls *.csv
  test_a_mysheet2.csv
 
# same thing but more closely mimicking LibreOffice output
$ ssconvert -S -O 'sheet=mysheet2 separator=, format=raw quoting-mode=never' Test.ods test_b_%s.txt;
$ mv test_b_mysheet2.txt test_b_mysheet2.csv;

# Q: But what if I don't know the sheet names?
# A: then you'll need to export everything
# notice the 'sheet' option is removed from the
# list of -O options vs previous command
$ ssconvert -S -O 'separator=, format=raw quoting-mode=never' Test.ods test_c_%n_%s.txt;
$ ls test_c*
  test_c_0_mysheet.txt    test_c_3_yoursheet2.txt
  test_c_1_mysheet2.txt   test_c_4_yoresheet.txt
  test_c_2_yoursheet.txt  test_c_5_holysheet.txt
  
# Now to rename all those *.txt files to *.csv
$ prename 's/\.txt/\.csv/g' test_c_*.txt
$ ls test_c*
  test_c_0_mysheet.csv    test_c_3_yoursheet2.csv
  test_c_1_mysheet2.csv   test_c_4_yoresheet.csv
  test_c_2_yoursheet.csv  test_c_5_holysheet.csv
  
zpangwin
  • 1,082
  • 1
  • 12
  • 17
0

Command:

soffice --headless "macro:///Library1.Module1.ConvertSheet(~/Desktop/Software/OpenOffice/examples/input/Test1.ods, Sheet2)"

Code:

Sub ConvertSheet( SpreadSheetPath as String, SheetNameSeek as String)
REM IN SpreadSheetPath is the FULL PATH and file
REM IN SheetName sheet name to be found and converted to CSV

Dim Doc As Object  
Dim Dummy()

SheetNameSeek=trim(SheetNameSeek)

If (Not GlobalScope.BasicLibraries.isLibraryLoaded("Tools")) Then
  GlobalScope.BasicLibraries.LoadLibrary("Tools")
End If

REM content of an opened window can be replaced with the help of the frame parameter and SearchFlags:

SearchFlags = com.sun.star.frame.FrameSearchFlag.CREATE + _
com.sun.star.frame.FrameSearchFlag.ALL

REM Set up a propval object to store the filter properties
Dim Propval(1) as New com.sun.star.beans.PropertyValue
Propval(0).Name = "FilterName"
Propval(0).Value = "Text - txt - csv (StarCalc)"
Propval(1).Name = "FilterOptions"
Propval(1).Value = "44,34,76,1"

Url=ConvertToUrl(SpreadSheetPath)

  Doc = StarDesktop.loadComponentFromURL(Url, "MyFrame", _SearchFlags, Dummy)
  FileN=FileNameoutofPath(Url)

  BaseFilename = Tools.Strings.GetFileNameWithoutExtension(FileN)

  DirLoc=DirectoryNameoutofPath(ConvertFromUrl(Url),"/")+"/"

  Sheets = Doc.Sheets

  NumSheets = Sheets.Count - 1
    For J = 0 to NumSheets

        SheetName = Sheets(J).Name

        if (SheetName = SheetNameSeek)  then

          Doc.getCurrentController.setActiveSheet(Sheets(J))        

          Filename = DirLoc + BaseFilename + "."+ SheetName + ".csv"

          FileURL = convertToURL(Filename)

          Doc.StoreAsURL(FileURL, Propval())             
    end if
    Next J
Doc.close(true)
NextFile = Dir
End Sub
halfer
  • 19,824
  • 17
  • 99
  • 186
  • Thank you for your reply. The script will be running on production server. I will have to check if I am able to add macros to Libreoffice there. – Andrey Jul 10 '19 at 14:21
  • Macros is not an option. I cannot believe even after releasing version 6 of Libreoffice they still do not support saving a specific tab – Andrey Oct 04 '19 at 18:06
0

I ended up using xlsx2csv Version 0.7.8 supports general xlsx files pretty well. It allows to specify the tab by number and by name.

It does not do a good job on macros and complication multi-sheet documents, but it does a very good job on regular multi-sheet xlsx documents.

Unfortunately, xlsx2csv does not support password protected xlsx, so for that I still have to use Win32::OLE Perl module and run it on Windows environment.

From what I can see Libreoffice still does not have the ability to select the tab via command line.

Andrey
  • 1,808
  • 1
  • 16
  • 28