4

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.

Community
  • 1
  • 1
  • Note, in the original post the desired result was `(("aaa" "bbb") ("ccc" "ddd") ("blah"))`. That is what my first solution delivers. The solution for the new demand `(("test") ("aaa" "bbb") ("ccc" "ddd=eee"))` is now added to my answer below. – Tobias Jul 14 '14 at 10:49

1 Answers1

3

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"))
Tobias
  • 5,038
  • 1
  • 18
  • 39
  • Thanks for that! I had gotten as far as your first example but ran into the "eee" problem. I don't quite understand how your second example works? Could you explain further? – Tim 'mithro' Ansell Jul 11 '14 at 03:45
  • Hi Tobias, I finally tested your second example and it doesn't fix the "eee" issue. – Tim 'mithro' Ansell Jul 14 '14 at 02:33
  • @tim-mithro-ansell That is interesting because it runs fine for me. I added the output I got in the scratch buffer. (Could you run it in the scratch buffer exactly as it is? Best regards, Tobias – Tobias Jul 14 '14 at 07:37
  • @tim-mithro-ansell Now, I read the edit of your question. You added a new requirement. In the former version you demanded `("ccc" "ddd")` for `--ccc=ddd=eee`. Now, you demand `("ccc" "ddd=eee")`. I will modify my answer to meet this demand when I have some spare time. – Tobias Jul 14 '14 at 08:07
  • Ahh sorry, I got my example wrong. Thanks for the fixed version, it works perfectly! – Tim 'mithro' Ansell Jul 15 '14 at 04:01