Is there something like brace expansion in bash or zsh for eshell?

For those unfamiliar with brace expansion: it is a part of shell expansion in some shells, such as bash or zsh that works as follows: if a word contains a list of words in braces, you get a list of copies of the word with the part in braces replaced by each of the words in the list in turn. This is clearer with an example: the command blah x{a,b,c}y is transformed to blah xay xby xcy by shell expansion, before running blah.


Assuming that @rekado is right and there is no builtin, I wrote this short function that does brace-like expansion:

(defun be (&rest args)
   ((null args) '(""))
   ((null (cdr args))
    (let ((hd (car args)))
       ((vectorp hd) (cl-mapcan #'be hd))
       ((listp hd) (apply #'be hd))
       ((atom hd) (list (format "%s" hd))))))
   (t (let ((be-tl (be (cdr args)))
            (r '()))
        (dolist (x (be (car args)))
          (dolist (y be-tl)
            (push (concat x y) r)))
        (reverse r)))))

It uses lists (or simply passing multiple arguments) for sequencing and vectors to indicate choice. The atoms can be given as strings, symbols or numbers. For example:

bash$ echo a{b,c{d,e}f}{g,h}i
abgi abhi acdfgi acdfhi acefgi acefhi

(be '(a [b (c [d e] f)] [g h] i))
("abgi" "abhi" "acdfgi" "acdfhi" "acefgi" "acefhi")

(be 'a [b (c [d e] f)] [g h] 'i)
("abgi" "abhi" "acdfgi" "acdfhi" "acefgi" "acefhi")

As far as I know there is no built-in support for brace expansion. You can, however, use plain elisp:

ls -la (mapcar (lambda (x) (concat "prefix-" x ".suffix")) '("A" "B" "C"))

This will run ls -la on the list ("prefix-A.suffix" "prefix-B.suffix" "prefix-C.suffix").

Here's another solution. Define this function:

(defun eshell-brace-expansion (str)
  (let* ((parts (split-string str "[{}]"))
         (prefix (car parts))
         (body   (nth 1 parts))
         (suffix (nth 2 parts)))
    (mapcar (lambda (x) (concat prefix x suffix))
            (split-string body ","))))

Then use this on the eshell prompt:

ls (eshell-brace-expansion "prefix-{A,B,C}.suffix")

Or this if you prefer:

ls "prefix-{A,B,C}.suffix"(|eshell-brace-expansion)

Maybe automatic handling of braces should be added to eshell upstream.

  • Thanks for your answer, I didn't now about the postfix (|fun) notation. I'll write a function that lets you use as many braces as you want (yours handles only one set) and that automatically applies symbol-name to symbols. That should be convenient enough for me to use. – Omar Feb 24 '15 at 15:29
  • If this answers your question please consider accepting the answer. If you do write a more flexible version please also consider posting it to the emacs-devel mailing list. – rekado Feb 24 '15 at 16:11
  • I was too lazy to do a general version that parses an input string as your eshell-brace-expansion function does. Instead I wrote a function that takes elisp structures, that I added to the end of the question. That sufficiently scratches my itch. – Omar Feb 24 '15 at 16:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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