Convert command line arguments to list in Emacs Lisp

command-line, command-line-arguments, elisp, emacs

Solution

You can use `split-string`. See the following code example.

(setq cmd-line '("--aaa=bbb" "--ccc=ddd=eee" "--blah"))
(setq cmd-line (mapcar (lambda (argstr)
             (when (string-match "^--" argstr)
               (split-string (substring argstr 2) "=")))
               cmd-line))

The output is `(("aaa" "bbb") ("ccc" "ddd" "eee") ("blah"))`. That is not exactly what you want because of `"eee"`. Maybe you can use that and just neglect `"eee"`.

If the `"eee"` is really a problem a small modification helps:

(setq cmd-line '("--aaa=bbb" "--ccc=ddd=eee" "--blah"))

(setq cmd-line (mapcar (lambda (arg)
             (when (string-match "^--" arg)
               (setq arg (split-string (substring arg 2) "="))
               (if (cdr arg)
                   (setcdr (cdr arg) nil))
               arg))
               cmd-line))

The output is:

(("aaa" "bbb") ("ccc" "ddd") ("blah"))

Variant for the new requirement in the question:

(setq cmd-line '("--aaa=bbb" "--ccc=ddd=eee" "--blah"))

(setq cmd-line (mapcar (lambda (arg)
             (when (string-match "^--\\([^=]*\\)\\(?:=\\(.*\\)\\)?" arg)
               (let ((opt (match-string 1 arg))
                 (val (match-string 2 arg)))
                 (if val
                 (list opt val)
                   (list opt)))))
            cmd-line))

The output is:

(("aaa" "bbb") ("ccc" "ddd=eee") ("blah"))

Problem

In an automated Emacs Lisp `--batch/--script` script I need to process the command line arguments given to the script. I've gotten as far as getting the arguments into a list of the the form: ``` ("--aaa=bbb" "--ccc=ddd=eee" "--blah") ``` Now, I need to convert them to a list of the form: ``` (("aaa" "bbb") ("ccc" "ddd=eee") ("blah")) ``` In Python I'd write something like; ``` output = [] for v in input: output.append(v[2:].split("=", 1)) ``` But have been unable to convert that code to Emacs Lisp. I found Elisp split-string function to split a string by . character but wasn't able to figure out how to make it only split on the first equals. I was heading down a route of using `(substring "abcdefg" x x)` with `(search)` from the `cl` package but it felt like there should be a better way? I think also want to use `(mapc '<function> input)` where function does the `v[2:].split("=",1)` part.

Original source

Related problems