Comment by susam

5 months ago

Excellent project! Thanks for sharing it here!

I'd just like to share my joy in using the Emacs shell (Eshell), which I find to be a wonderful fusion of the Unix shell and a Lisp REPL. You can enter commands with or without parentheses. For example:

  ~ $ concat "foo" "bar"
  foobar
  ~ $ (concat "foo" "bar")
  foobar

Or

  ~ $ * 123 456
  56088
  ~ $ (* 123 456)
  56088

Eshell comes with several built-in commands implemented as Elisp functions. For example:

  ~ $ which cd echo ls which
  eshell/cd is a byte-compiled Lisp function in ‘em-dirs.el’.
  eshell/echo is a byte-compiled Lisp function in ‘em-basic.el’.
  eshell/ls is a byte-compiled Lisp function in ‘em-ls.el’.
  eshell/which is a byte-compiled Lisp function in ‘esh-cmd.el’.
 ~ $ ls -l /etc/h*
  -rw-r--r--   1 root           wheel         446 2025-02-15 20:43 /etc/hosts
  -rw-r--r--   1 root           wheel           0 2024-10-01  2024 /etc/ hosts.equiv
  ~ $ (eshell/ls "-l" (eshell-extended-glob "/etc/h*"))
  -rw-r--r--   1 root           wheel         446 2025-02-15 20:43 /etc/hosts
  -rw-r--r--   1 root           wheel           0 2024-10-01  2024 /etc/hosts.equiv

Of course, you can still run external commands like usual:

  ~ $ which curl jq python3 rustc
  /usr/bin/curl
  /opt/homebrew/bin/jq
  /opt/homebrew/bin/python3
  /Users/susam/.cargo/bin/rustc
  ~ $ python3 -c "print('hello')"
  hello
  ~ $ curl -sS https://hacker-news.firebaseio.com/v0/item/43061183.json | jq -r .title
  Schemesh: Fusion between Unix shell and Lisp REPL

Since TRAMP is an integral part of Emacs, you can switch between the local shell and remote shells transparently with simple 'cd' commands. For example:

  ~ $ echo local > /tmp/foo.txt
  ~ $ echo remote > /ssh:susam@susam.net:/tmp/foo.txt
  ~ $ cd /tmp/
  /tmp $ cat foo.txt
  local
  /tmp $ hostname
  mac.local
  ~ $ cd /ssh:susam@susam.net:/tmp/
  /ssh:susam@susam.net:/tmp $ hostname
  susam.net
  /ssh:susam@susam.net:/tmp $ cat foo.txt
  remote

In the second command, I redirected a file to a remote file system with the usual '>' redirection operator.

Notice how, in the sixth command, I switched from my local shell to a remote shell with a simple 'cd' command. With Eshell and TRAMP, working across multiple remote systems becomes transparent, seamless, and effortless! Best of all, I still have the full power of Emacs at my fingertips, making Eshell an incredibly smooth and powerful experience!

When eshell runs a pipeline of external programs, does it fork+exec them all in parallel and connect them with the requisite file descriptors? Or does it run each program sequentially, grabbing its output in its entirety before passing it onto the next program in the pipeline?

I thought it was the latter (but it's been a while since I looked at it).

Tcl's exec gets it right. R Keene's pipethread extension for tcl gets it even more right.

Just perusing the schemesh docs (haven't tried it yet), it looks like he got it right, as well

Eshell looks really powerful :)

Does it also have job control, and jobs as first-class objects?

In schemesh, you can do things like

    find / -xdev -type f | ls -l --sort=size
    CTRL+Z
    bg 1

and also

    (define j {git log})
    (display j)
    (display (sh-run/string j))

  • Unfortunately, Eshell does not have job control. Quoting from <https://www.gnu.org/software/emacs/manual/html_mono/eshell.h...>:

    > A command invocation followed by an ampersand (&) will be run in the background. Eshell has no job control, so you can not suspend or background the current process, or bring a background process into the foreground. That said, background processes invoked from Eshell can be controlled the same way as any other background process in Emacs.

    For things like this, we would have to switch to something like M-x shell or even M-x ansi-term. In Emacs, we have an assortment of shells and terminal implementations. As a long time Emacs user, I know when to use which, so it does not bother me. However, I can imagine how this might feel cumbersome for newer Emacs users.

    In fact, this is one of the reasons I think your project is fantastic. It offers some of the Eshell-like experience, and more, to non-Emacs users, which is very compelling!

    • > Unfortunately, Eshell does not have job control.

      I wonder why, after all these years, nobody has added it?

      If someone (not me) made a patch that did, would the GNU Emacs maintainers accept it?

      2 replies →

I think the tramp feature is particularly useful. Bash is sticky because it will be the default on any box. Learning a second syntax or a set of subtle differences from bash can become necessary when you are using shells on many boxes. Tramp means you get edged on remote boxes (sort-of, I suppose)