This problem is so convoluted that maybe I should call it a puzzle...


On the Unix shell command line, I can convert TSV (tab-separated-values) input to org-mode table format with this perl one-liner:

perl -lpe 's/(?:^|$|\t)/|/g'

So, for example, I can write something like

<<<pipeline producing TSV rows>>> | perl -lpe 's/(?:^|$|\t)/|/g' > mytable.org

The contents of mytable.org would be a valid org-mode table, but it would not be nicely formatted.

For example, if <<<pipeline producing TSV rows>>> produced the following

1   ABCDEFG
234567  HIJKLMNO
890123  P

...the contents of mytable.org would be

|1|ABCDEFG|
|234567|HIJKLMNO|
|890123|P|

To format it nicely, I could

  1. open mytable.org with Emacs;
  2. set the major mode to org-mode (if it doesn't happen by default);
  3. hit C-c C-c, aka org-ctrl-c-ctrl-c-hook, which has the effect of reformatting the table so that the delimiters line up; and
  4. save the file;

...after which the contents of mytable.org would look like this

|      1 | ABCDEFG  |
| 234567 | HIJKLMNO |
| 890123 | P        |

My question is, how can I perform this reformating operation from the command line, without having to start an interactive Emacs session?

More specifically, is there a way to implement a pipeline component, that uses Emacs, and that I can insert right before the output redirection > mytable.org, like this

<<<pipeline producing TSV rows>>> | perl -lpe 's/(?:^|$|\t)/|/g' \
    | format-org-table > mytable.org

...that it would achieve the same final form of mytable.org as shown earlier? The goal here is to avoid the need to "manually" open mytable.org with Emacs, then hit C-c C-c, etc.

  • Take a look at using Emacs in noninteractive batch mode. – Dan Nov 18 at 18:58
up vote 1 down vote accepted

You can try the following:

;;; csv-to-org-table.el --- Convert CSV to Org table  -*- lexical-binding: t; -*-

;;; Commentary:

;; Example:
;; 
;; ~ $ echo "a\tb\n1\t2" | emacs --batch -l csv-to-org-table.el
;; | a | b |
;; | 1 | 2 |

;;; Code:

(insert-file-contents "/dev/stdin")

(if (zerop (buffer-size))
    (kill-emacs)
  (require 'org)
  (org-table-convert-region (point-min) (point-max))
  (princ (buffer-string)))

;;; csv-to-org-table.el ends here

If you prefer format-org-table to emacs --batch -l csv-to-org-table.el, you can create an Emacs Lisp script or shell alias/function.


However, it is better to use a proper programming language and implement org-table-convert-region from scratch, I don't think it will be difficult.

  • Thank you! Out of curiosity, is there a problem with replacing the (if (zerop (buffer-size)) ... with (unless (zerop (buffer-size)) ..., getting rid of the (kill-emacs), and putting the remaining expressions in a (progn ...)? – kjo Nov 19 at 22:46
  • 1
    @kjo No problem. It is actually better. The above code is ported from github.com/xuchunyang/emacs.d/blob/master/bin/csv-to-org-table, somehow (kill-emacs) is used. – xuchunyang Nov 20 at 2:56

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.