Presenting Eshell
Outline
- Introduction:
- Typical Shell Features
- Typical Lisp REPL features:
- Advanced Features
- Modifications/Extensions:
Note: We must make this into a workshop … type this, then this.
Introduction
John Wiegley created EShell in 1998:
…as a way to provide a UNIX-like environment on a Windows NT machine.
Part of Emacs since v21.
Personally?
- Started with
ksh - Used a lot of shells…
- Tried
eshellsoon after its birth - Shelved it since it wasn’t shell-enough
- Rediscovered years later
- Finally got it…
What’s all this then?
- What eshell really is
- How to use
Hacking
FYI: Deep content coming up… Watch this as a recording later (I’ll upload this org-mode file)
Shell… The Good
- Can be immensely powerful… at times
- Pipes and redirection are a staple
- Utilizing small, focused text-oriented executables
- Complex command re-invocation (aka. shell history)
Shell… The Bad
- Commands? Like key sequences, only longer
- Needing completion to run commands?
- Loops? Not terrible
Shell… The WTF?
- Best part: extensibility!
But what an awful language:
if [ $(echo "$IN" | cut -c 1-3 ) == 'abc' ]; then # ... fi
- May be Turing complete, but so what.
But, but, but… we know the shell!
iPython
Python REPL with shell-like features.
- Understands a current directory
- Has some shell-like commands,
cat - Doesn’t easily execute programs:
system - Executes Python scripts:
run
EShell as a Shell
- Most “interactive language” interfaces choose:
- Language-specific REPL
- Shell-focused program worker
- Eshell marries both pretty well:
- Concept of a current directory
popd,pushd, anddirs- Globbing Expressions
- Aliases:
alias ll 'ls -l'
- Tempted to think
eshellis likeshell
EShell as a REPL
- Lisp expressions just work with parens
- Parens kinda optional (more later)
- Eshell distinguishes numbers from strings
- Quotes often optional
- Do you care about spaces?
- Double and single quotes are interchangeable
Function or Executable?
What about the executable find vs.
Emacs’ find function?
Precedence Order:
- Eshell aliases
- Emacs functions that being with
eshell/prefix - Normal Emacs functions
(don’t need to be
interactive) - Shell executables
Of course, this is customizable:
eshell-prefer-lisp-functionsprefer Lisp functions to external commandseshell-prefer-lisp-variablesprefer Lisp variables to environmentals
Functions should assume &rest for arguments:
(defun eshell/do-work (&rest args) "Do some work in an optional directory." (let ((some-dir (if args (pop args) default-directory))) (message "Work in %s" some-dir)))
Eshell’s Parser Expressions
eshell… can you say braces?- no parens
- assumes strings and globs $vars
{ ... }- grouping expressions
${ ... }- evaluation for strings
elisp… all parens all the time( ... )- is fully Lisp-centric
$( ... )- evaluation for strings and string substitution
Note: You can mix your expression parsing
Shell-like Loops
- Syntactic sugar around
loop. - Code following
inis a generate list - Use trailing
{ ... }for side-effects
Globbin’ Filters
- The
*glob-thing has filters - Great if you can remember the syntax:
.for files/for directoriesrif readablewif writableLfiltering based on file sizemfiltering on modification time
- The filters can be stacked, e.g.
.L
Modifiers
Got a list of files?
Syntactic sugar to convert strings and lists.
Eshell filters and modifiers remind me of regular expressions
Don’t know the eshell-way? Just drizzle Lisp.
EShell Hack Points
While offering similar shell experience, Eshell is really hackable!
Extending Predicates
The User predicate (U) could have been written:
(defun file-owned-current-uid-p (file) (if (file-exists-p file) (= (nth 2 (file-attributes file)) (user-uid))))
Then add it:
(add-hook 'eshell-pred-load-hook (lambda () (add-to-list 'eshell-predicate-alist '(?U . 'file-owned-current-uid-p))))
I have a directory stuffed with files.
Most of my files have #+tags entries.
I can filter based on these tag entries.
I have to parse text following predicate key.
Remote Connections
To have eshell work on a remote server:
(let ((default-directory "/ssh:your-host.com:public/")) (eshell))
My personal project:
- Connect to my hypervisor controller
- Download and store a list of virtual machines
- Use
ido-completing-readto select a host / ip - Generate a Tramp URL for
default-directory
Replacing Pipes
Pipes are Flexible, but…
- Shell’s text processing is limited
- Using arsenal of tiny, cryptic programs
- Re-run many times since debug pipe steps
Instead, redirect output to Emacs buffer:
$ some-command > #<buffer buf-name>
Reference buffers as #<buf-name> with:
(setq eshell-buffer-shorthand t)
Emacs is pretty good at text processing
keep-lines/flush-linesinstead ofgrepreplace-string, et. al instead ofsed
Been thinking of something like:
$ openstack server list > pipe-edit saved-results.txt
Eshell Summary
- Advantages:
- Similar shell experience between operating systems
- Much more extendable, hackable and funner
- Disadvantages:
- Pipes go through Emacs buffers… not efficient
Programs that need special displays:
(add-to-list 'eshell-visual-commands "top")