6

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.

EDIT:

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

(defun be (&rest args)
  (cond
   ((null args) '(""))
   ((null (cdr args))
    (let ((hd (car args)))
      (cond
       ((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")
Omar
  • 4,812
  • 1
  • 18
  • 33

1 Answers1

6

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. –  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