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.