https://www.masteringemacs.org/article/complete-guide-mastering-eshell
Toggle menu
Mastering Emacs
* About
* Article Index
* Reading Guide
* My Emacs Packages
The Mastering Emacs ebook cover art
Emacs 28 Edition is out now!
Read a Free Sample
---------------------------------------------------------------------
Learn More
Mastering Eshell
Emacs has a shell written entirely in Emacs Lisp. Here's how you
master Eshell, a versatile and powerful shell capable of supplanting
bash or zsh as your daily driver. [vintage-co]
By Mickey Petersen
[fleuron2]
You can run Run Shells and Terminal Emulators in Emacs, but none can
match the versatility and integration with Emacs like Eshell.
Eshell is a shell written entirely in Emacs Lisp, and it replicates
most of the features and commands from GNU CoreUtils and the
Bourne-like shells. So by re-writing common commands like ls and cp
in Emacs-Lisp, Eshell will function identically on any environment
Emacs itself runs on.
Unlike a terminal emulator, Eshell is more like bash, zsh or the
python shells. That means it has its own idiosyncrasies, rules, modes
of operation, advantages and disadvantages.
Eshell in action. Using Tramp you can cd into remote
systems. Here it's a docker container running locally. Eshell in
action. Using Tramp you can cd into remote systems. Here it's a
docker container running locally.
The main advantage is that you're just talking to Emacs. The
downside, of course, is that it's not a shell you're probably
familiar with: it'll bear many similarities to the likes of bash or
zsh, but it's distinctly none of those things also.
So why use it? Well...
Native Tramp Support
So you can cd into docker containers; remote SSH servers; Android
phones using the Android Debug Bridge; talk to anything rclone
works with, like S3; su and sudo; and much more. And you can
combine them all - SSH to this host, then sudo to this user - all
from within Emacs and Eshell.
All of this, of course, is also available to Emacs writ large.
Write Elisp instead of sh
It's got the full power of Emacs behind it.
+ Want to open a file? Type find-file and Emacs opens it.
+ Need a M-x dired buffer? Just type dired ..
+ Worried about the next full moon? Try lunar-phases.
Piping and Redirection is through Emacs
So you can redirect the output of a command straight into an
Emacs buffer or its kill ring.
It's all Emacs
For better or worse! You gain tight integration with your Emacs
environment, and extending Eshell is relatively easy, as it's all
elisp.
Command Interception
Type grep and instead of printing out the results like a normal
shell would, Emacs instead refers the query to its own grep
machinery, as if you'd called M-x grep.
Plan9 Smart Display
Instead of your screen tailing the output of a command, you can
tell Eshell to page top-to-bottom automatically when the output
exceeds what fits on your screen.
Excellent when you want to digest the output one page at a time.
... and much more!
Alas, there is also a small problem: Eshell is only partially
documented - a rare sight in GNU Emacs - so I've compiled this guide
to help people make full use of what Eshell has to offer. The
documentation is better today than it's been before, but there's
still a lot of "tribal knowledge" out there you should know about.
Overview
Unlike the other shells in Emacs, Eshell does not inherit from
comint-mode, the default mode for interacting with inferior processes
in Emacs. But because Eshell is not an inferior process, it does not
have to use comint; but while that may seem like a good thing, it
does mean that hooks and routines written for comint-mode won't work
with Eshell. That also means any key bindings and commands you may
know and use elsewhere may not work well in Eshell, or at all.
Nevertheless, Eshell does reproduce a selection of key bindings you
might know from comint-mode, and it does a reasonable job of
mirroring the semantics of some of the commands. One example of where
Eshell lags behind is that its history search, M-r in comint-mode
derivatives and Eshell, does not search-as-you-type.
Eshell works well on any platform Emacs itself runs on, as Eshell
interacts with a common middleware (namely Emacs, and Emacs in turn
talks to your operating system) and that opens up a number of
benefits if you're stuck running Emacs on a platform that does not
support common Linux paradigms. So you're likely to get a consistent
user experience when you use Eshell, and that's one of its strengths.
Another is that you get to benefit from native Tramp support, which
is another feather in its cap.
In fact, Eshell also works well with Windows-specific concepts, like
disk drives. So it's easy-peasy to just cd D: to change drives in
Windows. No need for any POSIX-style abstractions, like /cygdrive/c
in Cygwin.
Despite all the advantages offered by Eshell, there are some
disadvantages or gotchas you should keep in mind:
It's still not a terminal emulator
As I mentioned earlier, Eshell is not a terminal emulator. It is,
in actual fact, utterly incapable of handling anything but
line-based programs. Instead, it'll outsource the running of
interactive - visual in Eshell terminology - programs to a
dedicated terminal emulator, like M-x ansi-term.
Eshell is Emacs
That means you're hidebound by the limitations of Emacs. You're
not farming out the work of running programs to an external tool
like bash. So if Eshell hangs, your Emacs hangs.
Emacs is also responsible for reading and writing from programs.
That means it has to buffer text, and that is generally slower
than a program written in plain C.
Native elisp compilation definitely helps though.
Eshell is not
Although it is a reasonable facsimile of particularly bash and
zsh, it does not implement their scripting languages or all the
piping and redirection concepts you may know and love from bash.
In fact, unless you're really talented at distinguishing GNU
Coreutils from bash, you're likely to assume Eshell can (or
cannot) do something simply because that distinction is blurred
to most users.
Commands
Eshell is Emacs. And the command line is wired to talk directly to
the large library of Elisp commands at your disposal. That means it's
not only easy to write your own commands - just write a normal elisp
function and call it - but Eshell is also able to call them, with or
without arguments.
You're therefore free to type find-file hello.txt and have Emacs open
up hello.txt. No need to call emacsclient; though of course that also
works!
It's a cool feature and highlights the benefits of tightly coupling a
shell to Emacs.
Technical Details
All commands evaluated by Eshell have an evaluation order, which is
an ordered list your command must pass through to determine what part
of Eshell handles it. If there is nothing on the list that wants to
evaluate your command, then Eshell will reject it.
Assuming you want to execute the command cp, the evaluation order is:
1. Look for a shell-defined alias (alias command)
2. A full filepath (e.g. /bin/cp) runs cp in /bin
3. Look for the command prefix, eshell-explicit-command-char
(default is *), and if it is found then look for the command in
the search path.
4. Look for cp in the search path, $PATH (or eshell-path-env)
5. Look for a Lisp function named cp or the elisp function eshell/cp
The variable eshell-prefer-lisp-functions alters the evaluation
order. What that means is when it's set to t Eshell swaps the search
order of #4 and #5. If the command prefix is specified, though, this
directive is ignored.
Built-In Commands
Eshell has a handful of commands written in elisp that closely
emulate a large subset of GNU Coreutils. Those commands are called
"Alias functions."
Eshell only implements a subset of the functionality provided by the
real commands, but if you pass an unknown argument to Eshell it will
defer to the real commandline tool (if it is installed)
automatically.
Here's what Eshell currently re-implements in elisp:
cat, cp, ls, cd, export, dirs, du, echo, env, kill, ln, mkdir, mv,
alias, popd, pushd, pwd, rm, rmdir, time, umask.
There is a big emphasis on adhering to the original GNU
functionality, so the fact they are emulated is only a problem if you
don't have the underlying tool installed on your system.
Command Interception
Eshell has a cool mechanism where certain commands are intercepted
and passed on to Emacs proper. It's a bit like the ability to call
elisp directly in Eshell, but instead of just doing that, the command
is instead reinterpreted as the equivalent feature in Emacs.
For instance, Emacs has a large selection of grep-style commands
(like M-x grep) that it can run internally and enrich with clickable
hyperlinks to each match. Instead of typing M-x grep you can type
grep in Eshell and Emacs takes it from there.
Here's a selection of the supported commands:
agrep, diff, egrep, fgrep, glimpse, grep, info, jobs, locate,
man, occur, su, sudo, whoami.
But you can see a full list with C-u C-h a ^eshell/.
The commands su, sudo and whoami are Tramp-aware commands, so if you
are connected to a remote shell they work as expected.
Subshells
There are two types of Emacs subshells. The first one is $( ... )
(also ( ... )) that evaluates Lisp.
You can use $() to in-line an elisp form and use its output in much
the same way as you would in bash:
$ echo $(+ 1 2 3)
6
The only caveat here is you cannot use the backquote (backtick) to
spawn a subshell, but that syntax was never universally supported
anyway.
It's also possible (though I would not recommend it, for there are
cases where it does not work) to use a standard elisp form like this:
$ echo (+ 1 2 3)
6
But it does not work everywhere, so exercise caution.
The other is more like an actual subshell: ${ ... }. Note that it's
not as versatile as a regular subshell that you may know from bash
and the like.
$ echo ${echo $(+ 1 2 3)}
6
Useful Elisp Commands
There are a number of useful Eshell commands that you should know
about. You're of course not limited to these commands, but they're
either really useful and general, or made specifically to plug a hole
in Eshell's feature set.
listify ARGS
Parses an argument string into elisp list notation and prints it
to the screen. It's clever enough to handle both MS-DOS/Windows
and POSIX-style argument syntax.
$ listify 1 2 3
(1 2 3)
addpath PATH
Adds the argument, which must be a path, to the $PATH environment
variable. If no argument is specified the existing paths are
pretty-printed to the screen.
$ addpath
/usr/local/sbin/
/usr/local/bin/
[ ... ]
$ addpath /opt/mypath/
/usr/local/sbin:...:/opt/mypath/
unset ENV-VAR
Unsets an existing environment variable
find-file FILE
Finds the file FILE and opens it in Emacs. This function is Tramp
aware and will therefore work remotely.
dired DIRECTORY
Opens a dired buffer in DIRECTORY.
calc-eval EXPR
Runs EXPR through the Emacs calculator.
$ calc-eval (+ 1 2)
3
Note that it does not use Emacs's hyper-advanced symbolic,
reverse-polish notation calculator (bound to M-x calc or C-x * *)
upcase STR/downcase STR
Converts STR to upper- or lowercase.
vc-dir DIRECTORY
Reports the status of a version controlled directory (equivalent
to the status command in most VCS)
magit
Activates M-x magit's status page for current working directory.
(If you have Magit installed, that is!)
If you have not used Magit for all your git needs, check out An
introduction to Magit, an Emacs mode for Git.
ediff-files FILE1 FILE2
Diffs FILE1 and FILE2 using ediff, one of Emacs's diff engines.
find-name-dired DIR PATTERN
Calls out to the external program find and asks it to find all
PATTERN in DIR.
Don't forget to escape the glob patterns you pass to PATTERN.
Single quotes work well.
Note that most commands work well over Tramp (more on that below) so
you can definitely cd to a remote Tramp directory; invoke magit and
get a magit status screen for a remote directory.
Aliasing
alias ALIAS-NAME DEFINITION
Aliasing in Eshell works in much the same way as it does in other
mainstream shells, except you can freely mix elisp and Eshell
commands. The command alias takes an ALIAS-NAME and a DEFINITION. You
must enclose DEFINITION with single quotes.
You can environment variable-style notation known from other shells:
$1 for the first argument, $2 for the second, and so on. You can also
use $* to use all arguments, or omit them entirely as Eshell will
magically append them on to the end of a command if they weren't
referenced in the definition.
To delete an alias, simply leave out the DEFINITION argument. To list
all the aliases, leave out both arguments.
Eshell will write the alias definitions to eshell-aliases-file, which
in turn is governed by the eshell-directory-name
By default that location is ~/.emacs.d/.eshell/alias. Emacs commits
all alias changes to that file immediately.
Another useful thing to know is the auto-correcting aliasing. If you
repeatedly fumble the spelling of a command (governed by
eshell-bad-command-tolerance, which is 3 by default) Eshell pops up a
prompt asking you to alias it to another command.
If you don't like that, you can bump up the aforementioned variable
to a large number.
Useful Examples
Let's map the cumbersome command find-file to the more manageable ff:
alias ff 'find-file $1'
And let's map dired to d:
alias d 'dired $1'
This calls find without arguments on the present working directory.
Great for getting a recursive listing of all files and directories in
your current buffer in a M-x dired buffer.
alias fd 'find-dired $PWD ""'
Visual Commands
Some commands are too complex to be displayed by Eshell directly, and
require special handling. To most programs, tools like M-x shell and
M-x eshell are dumb terminals: they are not capable of advanced
cursor movement required for programs like emacs or top to work.
Eshell works well with line-based programs but not interactive
programs. For the latter you need a proper terminal emulator. Because
interactive (visual in Eshell speak) programs are common, you can
tell Eshell to open up visual commands in a dedicated terminal
emulator.
To modify the list of visual commands, you can alter
eshell-visual-commands. You can even put in commands that work fine
in Eshell if you'd rather they run from a dedicated terminal
emulator.
If a program requires a full-blown terminal emulator for only some of
its subcommands - git being one such example - you can customize
eshell-visual-subcommands and eshell-visual-options and selectively
enable visual command support:
(add-to-list 'eshell-visual-options '("git" "--help" "--paginate"))
(add-to-list 'eshell-visual-subcommands '("git" "log" "diff" "show"))
Invocations to git that include either one of --help or --paginate as
an option, or log, diff or show as a subcommand, are now invoked
through a terminal emulator.
Command History and Prompt Key Bindings
Eshell comes with a feature-rich command history facility. Because
Eshell does not use comint-mode it does not have all the history
features available to it, but most of the common ones do exist.
M-r / M-s
Search backwards or forwards for a command by regexp
M-p / M-n
Goes backwards or forwards in the command history list
C-c C-p / C-c C-n
Jump to the previous or next command prompt in Eshell
C-c M-r / C-c M-s
Jumps to the previous or next command that shares the command
currently used as input. So it jumps to other instances of the
command foo if that is the current input.
C-c C-o
Kills the output of the previous command.
C-a / C-e
Move to the beginning or end of line.
Unfortunately, the search-as-you-type history search in M-x shell
(bound to M-r) is not implemented in Eshell.
Because I program a lot, I tend to use M-m instead of C-a to move to
the beginning of the line. M-m skips indentation and moves to the
first non-whitespace char, unlike C-a.
That command does not work in Eshell, for obvious reasons, but you
can rebind it to the same key as C-a:
(define-key eshell-mode-map (kbd "M-m") 'eshell-bol)
History Interaction
You can rewrite previous commands found in Eshell's history. The
syntax is similar to what you find in bash, but it's just a subset of
the most common features. It's probably easier to refer you to the
bash info manual for detailed information on how the history
interaction works. I've included a small table below that describes
most of the history syntax Eshell supports.
You may also want to read my article on Shell & Comint Secrets:
History commands. Although it concerns comint-mode-derived things,
it's useful to know about anyway.
!!
Repeats the last command
!ls
Repeats the last command beginning with ls
!?ls
Repeats the last command containing ls
!ls:n
Extract the nth argument from the last command beginning with ls
!ls
Using pcomplete, show completion results matches ls
^old^new
Quick substitution. Using the last command, replaceold with new
and run it again. Appears to be buggy.
$_
Returns the last parameter in the last executed command.
Eshell also has some support for bash history modifiers (like !!:s/
old/new/) and the bash reference on history interaction would be a
good place to brush up on that.
Commandline Interaction
The Eshell Prompt
You can customize the Eshell prompt by modifying
eshell-prompt-function, a variable that takes a function that defines
what the prompt should contain. By relegating prompt configuration to
elisp you can do just about anything you like with it. The only
problem is, of course, that Eshell will need to be told what the
prompt "looks" like, so you must also edit the variable
eshell-prompt-regexp so Eshell knows what the prompt is.
Instead of going to the trouble of changing it yourself, you can give
the package Eshell prompt extras a try.
The Command Line
You can use \ to escape newlines and it supports rudimentary
multi-line input that way.
Another way of doing multi-line literal strings is with single
quotes: begin a single quote and hit enter, and you are free to enter
text until the closing quote delimiter is encountered. If you use
double quotes Eshell will expand subshell commands and do variable
expansion. In this sense it's quite similar to bash, though without
the support for bash heredocs.
Due to the way Eshell works, you can even go back and modify the text
you entered, in quotes.
Useful Keybindings
Eshell comes equipped with a couple of quality-of-life improvements
that make interacting with Emacs and Eshell a lot easier.
C-c M-b
Inserts the printed buffer name at point
C-c M-i
Inserts the printed process name at point
C-c M-v
Inserts an environment variable name at point
C-c M-d
Toggles between direct input and delayed input (send on RET).
Useful for some programs that don't work correctly with buffered
input.
Argument Predicates
Argument predicates are a cool way of quickly filtering lists of
files or even elisp lists. The predicate syntax is based on the one
used in zsh.
Unlike most other areas of Eshell, argument predicates are documented
in Eshell itself.
You can access the help files by typing eshell-display-predicate-help
or eshell-display-modifier-help in Eshell or M-x. If you frequently
use them, you should consider creating an Eshell alias.
Filtering globbed lists of files is very useful, as it saves you the
hassle of using tools like find to cut down on matches.
The help file is fairly spartan and only serves as a simple
reference, so I've included a small guide here. But actually, the
only real way to learn something as flexible as argument predication
istrial and error.
Syntax Reference
I've opted not to reprint the sizeable list of predicates and
modifiers, as the Eshell popup help (see the commands above) do a
good enough job of explaining how they work.
Globbing
Globbing in Eshell follow the same rules as it does in most other
common shells: it is the shell that does the expansion of globs and
it passes the expanded list of matches on to commands like ls. That's
why when you use find and xargs together it's critical that you pass
-print0 to find, and -0 to xargs. If you don't, filenames with
obscure characters or spaces in them may trip up xargs. Using the NUL
character as a separator ensures tokenization takes place correctly.
Elisp Lists
Eshell's "lists" are actually elisp lists in their printed form as
well as internally. That makes life a lot simpler if you think about
it, as Eshell can paw off list handling to elisp, which is something
Lisp does well.
Here is a common example
$ echo *
("bar" "bin/" "dev/" "etc/" "foo" "home/" "lib/" "tmp/" "usr/" "var/")
Like most shells everywhere, * is a wildcard glob pattern. Because -
as I just mentioned above - wildcard expansion takes place inline, I
can modify the output of a glob pattern like *.
Let's uppercase the globbed result set:
$ echo *(:U)
("BAR" "BIN/" "DEV/" "ETC/" "FOO" "HOME/" "LIB/" "TMP/" "USR/" "VAR/")
Notice how I used () immediately following the glob pattern.
Modifiers are things that modify (big surprise!) the resulting list.
Modifier commands always begin with :, and filtering predicates do
not.
Another example, but this time I filter directories using a
predicate:
$ echo *(^/)
("bar" "foo")
The circumflex, ^, in this case, like in regular expressions, is
negation. The / means "directories" only.
But I don't have to use globs to apply modifiers or predicates to
lists:
$ echo ("foo" "bar" "baz" "foo")(:gs/foo/blarg/)
("blarg" "bar" "baz" "blarg")
This time I replaced all occurrences of foo with blarg. Observe that
the syntax is identical, except instead of using globs to get a list
of files, I used a list of my own choosing.
The advantages provided by argument predicates and modifiers will
greatly reduce commandline clutter as the predicates cover
permissions, ownership, file attributes, and much more.
Adding New Modifiers and Predicates
You can even add your own predicates (eshell-predicate-alist) or
modifiers (eshell-modifier-alist):
(add-to-list 'eshell-modifier-alist '(?X . (lambda (lst) (mapcar 'rot13 lst))))
Here I've bound X to rot13, the substitution cipher:
$ echo ("foo" "bar" "baz")(:X)
("sbb" "one" "onm")
Plan 9 Smart Shell
Eshell comes with a pared-down facsimile of Plan 9's terminal, called
the Eshell smart display. The smart display is meant to improve the
write-run-revise cycle all command line hackers suffer through. It
works by not letting the point follow the output of a command you
execute, like a normal shell would. Instead, the point is kept on the
line of the command you executed, letting you revise it easily
without having to use M-p and M-n or the history modification
commands.
Additionally, you can 'peek' at long-running commands using SPC to
move down a page and BACKSPACE to move up a page while you wait for
the command to finish. Any other key press jumps to the end of the
buffer.
Essentially, if Eshell detects that you want to review the last
executed command, it will help you do so; if, on the other hand, you
do not then Eshell will jump to the end of the buffer instead. It's
pretty clever about it, and there are switches you can toggle to
fine-tune the behavior.
Where the smart display really shines is that it lets you modify the
command you just executed by using the movement keys - like you
normally would - to change the command, say to fix a typo or tweak an
argument.
You can also disable smart display so it won't activate if the
command you executed exited with code 0 (indicating success) and if
it finished without emitting any output.
To enable it put this in your init file:
(require 'eshell)
(require 'em-smart)
(setq eshell-where-to-jump 'begin)
(setq eshell-review-quick-commands nil)
(setq eshell-smart-space-goes-to-end t)
;; If the above does not work, try uncommenting this.
;; (add-to-list 'eshell-modules-list 'eshell-smart)
If Eshell is already initialized (that is, you've already launched an
instance of Eshell in Emacs) then evaluating the changes above will
not work. You must switch to the Eshell buffer and type M-:
(eshell-smart-initialize) (or restart Emacs.) You might see some
garbled output appear in your echo area. Just ignore it.
Some report that they must
So remember: SPC to page through the output; BACKSPACE to move back a
page; and any other keys jumps to the end of the buffer.
Redirection
Redirection in Eshell works in much the same way as it does in other
shells. The key difference is that Eshell has to emulate the
pseudo-devices as they may not be present (or may not be present in
the same form) on platforms such as Windows where /dev/null is
actually NUL.
Another caveat is that Eshell does not support input redirection,
though it does support output redirection. To skirt around the lack
of input redirection you should use pipes instead.
Redirection to stdout, stdin and stderr work as you would expect, and
you can send things to multiple targets as well, which is very nice.
Redirecting Pipes to a Buffer
Because Eshell has to reimplement pseudo-devices internally it is not
at the mercy of dealing with just UNIX device files - it is actually
capable of implementing its own pseudo-devices.
A good example would be redirection to a buffer of your choosing, and
that can be done with the following syntax:
$ cat mylog.log >> #
This is where the ability to insert the printed format of a buffer
comes in handy. The command C-c M-b from before does the job. There
is another shorthand: #<*scratch*> that achieves the same outcome.
You can also output straight to an elisp variable (but be careful you
don't fry the wrong settings):
$ echo foo bar baz > #'myvar
$ echo $(cadr myvar)
bar
If you set eshell-buffer-shorthand to t you can use the shorthand #
'*scratch* instead, but it means you will not be able to redirect
straight to elisp symbols. I recommend you use C-c M-b and #
instead.
To Pseudo-Devices
Eshell reimplements the following pseudo-devices:
/dev/eshell
Prints the output interactively to Eshell.
/dev/null
Sends the output to the NULL device.
/dev/clip
Sends the output to the clipboard.
/dev/kill
Sends the output to the kill ring.
The usual redirection rules like overwrite (>) and append (>>) apply
here.
To Custom Virtual Targets
You can design your own virtual targets by modifying
eshell-virtual-targets, an alist that takes the name of the
pseudo-device you want to create, and a function that takes one
parameter, mode, that determines if it's overwrite, append or insert.
Remote Access with Tramp
Tramp (Transparent Remote Access, Multiple Protocol) is a framework
for communicating across different user accounts, servers, docker
containers, and much more.
It's handy, and works well. Tramp works - keeping it simple, here -
by intercepting how Emacs interacts with files, directories and
processes. Because it's generic, it works with a huge range of
Emacs's features -- features that are almost never coded explicitly
with Tramp in mind.
Eshell works well with Tramp. Provided you follow Tramp's connection
notation, you can connect to any backend Tramp supports and interface
with it using Eshell.
Here's an example that changes directory to a remote server using
SSH:
cd /ssh:bob@initech:/srv/tps-reports/
That incantation connects as user bob to the server initech and
switches to its /srv/tps-reports/ directory. From that moment on, all
interactions in Eshell take place through the lens of the remote
connection you established through Tramp.
Tramp is not perfect; nor is Eshell. But a wide range of commands
work beautifully well remotely. Note that unlike an ordinary SSH
connection Tramp does, in actual fact, make distinct calls via SSH
every time you carry out an action.
It's not a longer-running session like you might expect, and although
you can configure all of this, it's worth bearing in mind that you're
reaching out and executing standalone actions, one at a time.
If you install the third-party package docker-tramp you can also cd
straight into docker containers and act on them.
Using that method, you can combine it with multi-hopping, so you can
SSH to a remote server then su to a different user; connect with
docker; or something else entirely:
$ cd /ssh:initech|su:root@localhost:/
Startup Scripts
Like most shells, Eshell supports both login and profile/rc shell
scripts. The full filepaths for both are stored in the variables
eshell-login-script and eshell-rc-script, but by default the files
login and profile are stored in ~/.emacs.d/.eshell/.
The comment syntax is #.
More Customization...
Eshell has hundreds of options you can tweak to your liking. To
configure Eshell, type M-x customize-group RET eshell RET.
Third-Party Extensions
There's a large body of third-party packages and snippets of code
available. Check your local package manager with M-x list-packages.
Use M-s o or / n to filter by package name.
Bookmarks & Project Integration
Emacs's extensive bookmarking facility also works with Eshell as of
Emacs 28. Create a bookmark with C-x r m and you can recall it at
will with C-x r l and friends.
I like this feature because you can bookmark directories and Emacs
can open up an Eshell at the exact place you bookmarked.
Likewise, Emacs's project management facility C-x p can open an
Eshell in your project root with C-x p e.
TAB Completion
Eshell has its own completion system called pcomplete. Although newer
versions of Emacs invoke the generic completion-at-point command, it
internally still uses pcomplete for much of the command completion.
I have an article where I talk about PComplete: Context-Sensitive
Completion in Emacs. If you ever want to extend Emacs's shell
completion - in newer Emacsen shell-mode also uses pcomplete behind
the scenes - or understand how it works, then that article's a good
place to start.
The completion system is not fool-proof, and unlike your favorite
external shell it does not come with an abundance of completion
libraries for every conceivable binary.
Nevertheless, both TAB and C-M-i offer completion at point.
And don't forget, Emacs has both M-x man and M-x woman for manual
page lookup.
Conclusion
I think I've covered all major areas of Eshell, and I hope it paints
it in a good light. Eshell is a versatile shell replacement thanks to
its tight integration with Emacs. It's not a drop-in replacement for
bash and your favorite terminal emulator, but it'll do most of the
command line stuff we all inevitably end up doing.
Eshell has Tramp support; custom pseudo-devices; a pocket-sized elisp
REPL; lots of useful utility commands like being able to find-file or
dired any directory or file you're in; and the ability to redirect
output from commands straight into a buffer.
All in all, it's a clever take on shells, and a tool I would
encourage you to experiment with.
Read a free sample chapter of Mastering Emacs
[ ]
[ ]
[Get Free Sample]
[fleuron1]
Further Reading
Have you read my Reading Guide yet? It's a curated guide to most of
my articles and I guarantee you'll learn something whether you're a
beginner or an expert. And why not check out my book?
Subscribe to the Mastering Emacs newsletter
I write infrequently, so go on -- sign up and receive an e-mail when I
write new articles
Email Address [ ]
First Name [ ]
[*]Would you like to read a free sample chapter of Mastering Emacs?
[ ]
[Subscribe]
[fleuron1]
I really appreciate this blog. You've made me more productive
already :)
Regarding globbing, I've noticed that globbing is unsorted by
default, which has been a bit of a hassle for me.
echo test_?_???.xml
vs
echo (sort (eshell-extended-glob "test_?_???.xml") 'string<)
Of course, the eshell 'ls' command does sort the output, which in
some way masks the issue.
-- llahwehttam * reply
That's peculiar. I can't seem to reproduce that on my machine.
$ echo test_?_??.xml
("test_1_10.xml" "test_1_11.xml" "test_1_12.xml" "test_2_12.xml" "test_3_12.xml")
Of course, if it is a problem, you can use the argument modifier
(:o) to sort a list.
-- mickey * reply
My use case is in a directory with a great deal of history, so
there's no telling the order of the directory entries.
Nonetheless, echo test_?_???.xml(:o) works quite well.
Thanks!
-- llahwehttam * reply
It took me a while to figure out for loops in eshell. Here are a
few examples:
for f in web1 web2 { scp info.php $f:/var/www/html/oscmax/catalog }
for f in {ls -1d *} {echo $f; svn up $f}
for f in {find . -name '*.java'} {mv $f (replace-regexp-in-string "\\.java$" ".scala" f)}
# Those parens may also be curly braces. Paren for lisp, curly for subshell.
# See how $f is used in curly brace but f is used in parens
for f in db1 db2 {mysqldump -d -uuser -ppwd (concat "prefix_" f "_suffix") >(concat "/tmp/backup_" f ".sql")}
-- Jim Menard * reply
Thanks for this. I use a lot of for loops in my daily bash
hacking but am moving more and more towards an emacs centric
perspective for everything I do!
-- Z * reply
Great article! Just wanted to point out a few things:
1. If you enable the optional "rebind" module, then all the
interactive keybinding you're familiar with in Bash will be
available at the Eshell prompt: C-r, C-s, C-w, C-u, etc. The
behavior of C-r here is perhaps similar to the new comint
functionality you mentioned.
2. eshell/X is always preferred to a native binary X.
3. You didn't mention >>> redirection, which inserts at point. >>
inserts at the end of the buffer.
4. All I/O in Eshell must passt through a buffer. This is why
devices can't be read/written directly. It also means that bulk I
/O in Eshell is orders of magnitude slower than a regular shell.
It should really only be used for interactive use.
5. Putting & at the end of a command backgrounds it, if the
command executed is external. But there is no job control.
6. Full Zsh globbing syntax is supported, like **/*.c.
John (Eshell author)
-- John Wiegley * reply
John,
Seems akismet ate your comment - sorry. Thanks for your feedback
(and for making Eshell a possibility), I'll update the article to
reflect your changes. Thanks!
-Mickey.
-- mickey * reply
> "6. Full Zsh globbing syntax is supported, like **/*.c."
Unfortunately eshell hands over the globbing string if nothing
matches. This can be worked around by adding a predicate, i.e.
"**/*.c(.)", but IMHO this is a design flaw. Opinions?
(zsh reports an error if nothing matches, I am not sure this is
the right thing to do either, but it prevents obscure errors.)
-- Ingolf Jandt * reply
all IO going through buffers: is it really necessary? I tend to
do a lot of sort+awk in my daily interactive shell usage - that's
pretty much all I do outside of emacs ;) I like the concept of
eshell, but because of the slowness I never manage to use it for
real work.
-- k * reply
You should check out my article on sorting in Emacs; you might be
surprised to learn that Emacs has excellent and regexp-aware
sorting mechanisms.
As for IO through buffers: that's pretty much how Emacs does the
bulk of its communications. As it goes, Emacs has thousands of
commands for operating on buffers but few that operate on
internal data structures, like strings, as it would unnecessarily
duplicate the functionality already available to a
near-infinite-length buffer.
-- mickey * reply
@mickey: thanks for the great article! It gave me the necessary
information to finally give eshell a proper try.
@john: based on your #4 comment I ran a test, using the command
"cat /usr/share/dict/words | wc -l". As expected, this runs MUCH
slower from eshell (tens of seconds) than from bash or fish
(instantaneous). However, I found worrying that the output from
the command changed too! From a regular shell (or by running "wc
-l /usr/share/dict/words" in eshell, without the pipe) I get the
correct result (235886 on my machine). However, from eshell I get
different lower numbers (it changes every time), including
174800, 226547, 224841, and others.
I can deal with I/O slowness since I know why it's happening, but
the risk of randomly incorrect output is more worrying. Do you
have any ideas about why this is happening?
Thanks for your work on Eshell!
-- Diego Zamboni * reply
Recently tested on bash and Eshell, both of them gave same result
:)
Thank you John and Mikey for Emacs awesomeness.
-- Abhishek Chandratre * reply
Nice post! Nice blog!
I find in eshell, when I run a command and redirect output to a
file, both stdout and stderr are redirected. I would expect only
stdout to be redirected, and stderr to be shown in the shell. But
I can't find any way to make it work that way.
So for example,
path/to/my/script > /path/to/my/file
will write *both* stdout and stderr to file. There's no way to
see stderr in the shell!
Thanks for the highly detailed original post. I'm curious if you
or anyone know how to solve this stderr problem.
-Dave
-- Dave Cohen * reply
You could try doing it with 1> and 2>. They should redirect
stdout and stderr specifically.
-- mickey * reply
No luck. Seems to treat 1> exactly the same as >. 2> seems to
have no effect.
I'm using a build of emacs 24.0.50.1 on arch linux. It's a dev
build, might have a bug not present in other versions.
-- Dave Cohen * reply
I have the same issue with Emacs 23.1.2 on Fedora.
-- Lukas * reply
One irritating thing about eshell, hitting C-a at the prompt does
not take you to the beginning of your input, but instead goes all
the way to the beginning of the shell prompt text. Useless!
-- Ghalib Suleiman * reply
Ok I just found out that the behaviour I want is the function
eshell-bol, bound to C-c C-a. by default.
-- Ghalib Suleiman * reply
It is also bound to C-a in Emacs 23.2 (at least)
-- mickey * reply
Thanks mickey, that was excellent. Perhaps GNU should adopt it
for the official documentation :)
-- Phil * reply
I hope this ends up in the GNU Emacs manual!
-- Alex Schroeder * reply
Thanks to mickey for sharing so many tips on using ESHELL. I have
discovered many new things here. Thanks.
I have one bug that is really annoying but I personally don't
know how to fix.
It can be reproduced following these simple steps:
1. Emacs -q
2. M-x eshell
3. cd /usr/include
4. ack time
After about 5 seconds, I see colours completely mixed up like
this http://i.imgur.com/Dg3VH.png even the ESHELL prompt is in
that disgusting colour.
Anyone has any idea how to fix that?
I have tried at least twice to fix it myself but unfortunately
due to the asynchronous nature of the process filter I alway gave
up in the end. The closest workaround I have found is:
(defadvice eshell-handle-ansi-color (around test activate)
"Handle ANSI color codes."
(ansi-color-apply-on-region (1- eshell-last-output-start)
(1- eshell-last-output-end)))
Leo
-- Leo * reply
Hmm. That stuff is always fiddly to deal with. I think the
easiest is to make an elisp eshell command called eshell/ack and
have it intercept the command and display the output in its own
buffer. Look at how eshell/grep and eshell-grep is implemented.
-- mickey * reply
Thanks for your prompt reply. Sorry it seems 'ack' caught your
attention. I only used it to demonstrate the problem.
-- Leo * reply
One thing I found lacking in eshell was the `find` utility. But
found it in the `find-lisp` library -- `find-lisp-find-files` and
`find-lisp-find-dired` (which could be aliased to `find` if
desired). Unfortunate about the missing input redirection, but
otherwise eshell is complete for my purposes!
-- ST * reply
(*Very* nice post by the way)
-- ST * reply
great article! it is frustrating to find good eshell docs.
-- brad clawsie * reply
What an excellent article -- Thanks a million!
Although I've been using Eshell on a regular basis, it'd never
have occured to me that all those nifty zsh predicates/modifiers
are working in eshell. The redirection features seem pretty nice
too.
-- danlei * reply
I am willing to user eshell instead of shell but I would like to
know better how to customize my eshell-prompt especially to
remain with ~ instead of the full path. Thanks.
-- Eugene * reply
Very nice article.
One thing that's continually kept me from adopting eshell is that
I work almost exclusively over Tramp, and every time I pass
eshell a non-built-in command, it takes a few seconds to open the
connection before I get my result.
With M-x shell, the connection is opened once at the beginning of
the session, and all subsequent commands execute immediately.
Does anyone have any experience with this or know of any
workarounds?
-- Selah * reply
I never knew eshell could do all these cool things, thanks!
One question though: In Bash, I use Alt+. all the time to cycle
through the last argument of previous commands. Is there anything
like it for eshell?
I read that the $_ variable gives me the last argument of the
previous command but that's only a small subset of what Alt+. in
Bash does.
Lukas
-- Lukas * reply
There is also a great deal of information about Eshell over at
EmacsWiki: http://www.emacswiki.org/emacs/CategoryEshell
-- Mathias Dahl * reply
This is maybe more of an Elisp question than an Eshell question,
but having the full path in the eshell prompt is driving me nuts.
There are some decent examples of changing your eshell prompt,
but how do I chop off all of the directories which are parents of
the CWD? Instead of /home/me/Sandbox/repo1/proj5/src/foo $ as my
prompt I just want foo $
Thanks
-- Z * reply
One more thought then I'll stop spamming your blog with comments:
I find the KDE file browser option to include a terminal in a
pane below the current directory really nice, as I navigate with
the gui file manager the terminal automagically cd's to the CWD.
Anybody know of any packages, or have thoughts on the difficulty
of emulating this behaviour between an eshell buffer and a dired
buffer? (This option is available in Konqueror as of at least KDE
3.5.x and also dolphin in KDE 4.x. An extension can be added to
the gnome file browser, nautilus to also enable this
functionality.)
-- Z * reply
You might want to use the function defined in this article to pop
in and out of an eshell-buffer.
http://howardism.org/Technical/Emacs/eshell-fun.html#sec-2
-- kluck * reply
Just a little detail (a possible typo). In the part about how one
can output to a symbol, I think it should be "echo $(cadr myvar)"
instead of "echo $(cadr foo)".
Thanks a bunch for this great article!
-- mk * reply
Good catch. Thanks!
-- mickey * reply
Just to point out a small typo.
When you said:
"You must switch to the Eshell buffer and type M-:
(shell-smart-initialize)"
you probably meant "M-: (eshell-smart-initialize)" right?
-- Anonymous * reply
Great catch. Thanks!
-- mickey * reply
hmm it looks like it is still there...
-- russ * reply
Superb article -- brilliant introduction to Eshell.
I have replace most of my Cygwin usage, was facing exactly the
same problems as you mentioned.
-- SomeOne * reply
alias cp 'cp -i $*' doesn't work for me. When I define this alias
I get "cp: missing destination file or directory". I'm using
emacs 23.3.
-- jj * reply
Oh, and thanks for the nice tutorial. :)
-- jj * reply
Does eshell have anything similar to dired's
(setq ls-lisp-verbosity nil)
to remove the uid and gid columns from
"ls -l" long-form directory listings?
(Emacs 24.0.92.1)
And yes, thanks for a terrific guide!
-- LongList * reply
Nice post. I'm just giving eshell a try, and so far I like it.
Especially since I don't need to omit "visual" commands like top,
which used to keep me away from emacs internal shells. (I don't
like M-x term. I can't cope with its bindings...
Now there're just a few things left to make me really enjoy
eshell for all my cmd line needs:
1. How can I teach it to show things like "git log" or "bzr log"
also in a term?
2. How can I configure this command interception?
-- Tassilo Horn * reply
Hi Tassilo,
1. You can tweak the list variable eshell-visual-commands
2. As for configuring it, you can try the customize group M-x
customize-group RET eshell-term RET
Thanks.
-- mickey * reply
1. The problem is that eshell-visual-commands have to be plain
commands whereas "git log" is a command with one argument
(subcommand). Adding "git log" to the list has no effect.
2. No, I've meant how to configure the *interception* feature.
M-x apropos-variable doesn't find any variable, M-x apropos finds
the function eshell-intercept-command, but that doesn't really
help me. How can I add other commands to be intercepted and their
output being shown in emacs itself?
-- Tassilo Horn * reply
Not sure if it's easily possible then as it's not something I've
ever had to do in eshell. You could probably ghetto some code but
I think this might be easier:
http://www.masteringemacs.org/articles/2012/01/16/
pcomplete-context-sensitive-completion-emacs/
My article on pcomplete (which is what eshell uses also) shows
how to intercept arguments to, coincidentally, git. You should be
able to use that to spawn a term session with a bit of elisp
hackery :)
-- mickey * reply
Hi Mickey,
I've added that feature to eshell. See http://
bzr.savannah.gnu.org/lh/emacs/trunk/revision/112822
Bye,
Tassilo
-- Tassilo Horn * reply
Impressive work, Tassilo! Thank you!
-- mickey * reply
Ok, thanks!
-- Tassilo Horn * reply
Hi, I had some trouble with recent emacs getting the smart shell
stuff to initialise, a recent patch looks to have taken all the
initialize function calls out of eshell hooks. Perhaps it all now
works in a different way but I couldn't see how.
I got it loaded with your additions plus
(add-hook 'eshell-mode-hook 'eshell-smart-initialize)
Nice post!
-- Matt Ford * reply
So far, I confess I have been very happy with eshell and outside
of a few warts where the TRAMP has failed me, I have had very few
issues.
Today, though, I hit a huge one. Why is it I can't run something
like:
echo "^hello^world"
I'm guessing it has to do with the reader macro, but the caret
symbol is hard to search for on google. Also, I found I can do
echo "^hello world."
It is only when the second caret appears that problems arise.
-- Josh Berry * reply
Great Emacs blog, is very useful for beginners. Like me
How I get this alias in eshell?
alias tif='ls *.{tif,tiff,TIFF,TIF}'
I want listing the tiff files only.
It works in bash.
Thank you
-- farliz * reply
Excuse my bad English!
-- farliz * reply
Brace-expansion is not a feature of eshell. You would either have
to create a function or create a fully qualified alias. alias tif
='ls *.tif *.tiff *.TIF *.TIFF'
-- Henrik Kjerringvag * reply
I think I may have found a typo: M-: (shell-smart-initialize)
should actually be ~M-: (shell-smart-initialize)~.
-- bryan * reply
Oops, didn't fix it there :p
I mean `M-: (eshell-smart-initialize)`
-- bryan * reply
Under "Technical Details" you describe the order commands are
evaluated in. However, when I use eshell it seems to prefer the
eshell versions of most commands, and even through the value of
`eshell-prefer-lisp-functions` is set to nil. Do you know if this
is something that has changed, or is it a bug maybe?
-- Ethan * reply
I recently bought your book and enjoyed it very much, but was
shocked to see this stuff about Eshell isn't in it! I'm not
crazy, am I? It's just not there?
-- Omar * reply
Great book! Made my emacs skills way better than my co-workers.
-- asingh * reply
Constructive criticism: I'm a longtime Emacs user, but I have
little experience with Eshell or child processes. So the first
two or three paragraphs of the "Overview" section are an annoying
tangent. I expected a handy introduction to Eshell and its
capabilities--- what's all this about comint-mode? When I first
read this article, I neither knew nor cared about comint-mode.
Those paragraphs would work better if located elsewhere, like in
a "Pros and Cons" or "Limitations" section.
Following the comint-mode paragraphs, there are a couple of
informative paragraphs about where Eshell runs, and how, and what
good that is. Then you finish the section with a list of things
that Eshell is not.
My suggestion is that you edit the "Overview" section to include
more introductory information about what Eshell is, how you
interact with it, etc., and move the non-overview information to
perhaps a "Pros and Cons" section.
I hope that doesn't sound too harsh. Other than for that, this
was an excellent article that taught me a lot about Eshell, and
makes me want to use it a lot more. Thank you very much!
-- Sue D. Nymme * reply
I've been using Eshell for six weeks now. Sadly, the fact that
for my job, I'm generating a couple of hundred million byte files
and the "even redirected output needs to pass through an Emacs
buffer" is starting
to really hurt (because it's sooooo slow). Not sure whether I
should start looking at whether I can live with "shell".
-- Steve Biederman * reply
In your mastering eshell section, it seems to me that points 4 &5
in the eshell order of evaluation list are the wrong way around.
eshell takes priority over builtins.
-- Richard Riley * reply
To get Plan 9 Smart Shell (smart display) working, I had to add
eshell-smart to eshell-modules-list with (add-to-list
'eshell-modules-list 'eshell-smart)
-- Josh Wheeler * reply
for your 'calc-eval' example, the arguments need to be enclosed
withing quotes. so it should look something like
'calc-eval "1 + 2"'
--
best regards
anupam
-- Anupam Kapoor * reply
Thanks, Anupam. Seems it's been changed from the older calc
implementation. I'll amend the article!
-- Mickey * reply
[fleuron1]
Name
[ ]
Email
[ ]
Website
[ ]
C-x C-f is what command?
[ ]
Comment Content
[ ]
Comment Cancel
Copyright 2010-22 Mickey Petersen. Terms & Privacy Policy. Updated
2022-05-24.