00:02.940 Introduction
00:37.881 What do I mean by shell?
01:38.560 What I do not mean
04:50.160 What is a shell?
09:26.912 Launching external processes
11:57.300 Environment variables
14:54.400 Processes
17:00.180 Redirecting and pipelining input and output
20:09.440 Scripts
21:11.780 File system management
23:43.560 Networking
24:30.120 A brief tour of Eshell
34:21.128 Login shell
36:36.980 Resources
A shell, such as Bash, is fundamentally an
interface to your operating system. It allows you
to run programs, direct I/O, manage processes, and
interact with the file system, as well as script
such activities. Allowing for a few caveats, we
can see that Emacs is capable of doing all these
things, and therefore Emacs can be used a
practical replacement for the traditional shell.
This talk aims to explain this philosophy, to
explore Emacs' basic shell functionality, and to
address various caveats.
a nice interface for using process filters directly sounds really
useful, reminds me of emacs-piper
Uniline?
lispmacs[work]: gs-101: yes
feels like a museum to see someone using helm x)
lispmacs[work]: heh heh
lispmacs[work]: it was the first one I learned, now I'm hooked
gs-101: First one I used was Ivy + Counsel, but then I moved to the Vertico + Consult stack as it was newer.
lispmacs[work]: I haven't had any pressuring motivations to try anything else yet, but am open minded
Is there a convenient way to share shell history between Eshell and the system shell (fish in my case)?
lispmacs[work]: I know there is, but I don't use it. let me check the eshell modules list
I use atuin and eshell-atuin to share shell history across programs, shells and machines.
Ah yes, I gave atuin a try some time ago but I hate that it takes over full terminal for history. Not sure if that changed now though.
lispmacs[work]: I'm not seeing something like that in the built-in Eshell Modules List unless eshell-hist does something like that
i use my consult-shell-command package which is a small wrapper around async-shell-command that also suggests shell history https://codeberg.org/mekeor/consult-shell-command
atuin is a CLI utility; eshell-atuin is a third party Emacs package. (https://github.com/SqrtMinusOne/eshell-atuin/)
there is also https://github.com/svaante/recall by dape.el-developer with a similar goal
I need to look more into Eshell. Just started using native Emacs on Windows and switched from cmd.exe in shell mode to PowerShell, but it would be nice to have a better shell that I can use both on my home machines and the two work machines that run GNU/Linux that would also work on my work Windows laptop.
Yes, I saw that's one of the main use cases for eshell. But on windows, for some reason, git provides a bash shell. https://gitforwindows.org/
Yes, I was thinking to maybe hook that into shell mode. The advantage of Eshell would be that I would not have to configure shell mode at all and just use the built in functionality of Emacs no matter what system I am on.
Using buffers for input and output is such a killer feature
Do you mean in eshell or more generally in Emacs
both! But particularly in eshell
How do you use a buffer as input in eshell?
That looks really cool!
wow!
I don't see an eshell/@ command, I think I missed something
Oh, it's piping (buffer-string). I think this should be (buffer-substring-no-properties (point-min) (point-max)) Otherwise you'll pipe propertized text causing issues with shell commands. (Unless the eshell pipe somehow strips text properties, which I doubt.)
lispmacs[work]: oh okay, I wonder if the eshell pipe gets rid of that on its own
There's also https://github.com/szermatt/emacsclient-commands which has an epipe utility
Input redirection from buffers in eshell would be great -- actually, input redirection at all would be great.
isn't the "solution" to use cat input | ...?
What is input here?
what's the use case of #\ or #\<NAME> notation in eshell, as described at (info "(eshell) Arguments")?
It's useful for redirection. run-foo > #\
ah right, described at (info "(eshell) Pipelines")
I just canβt get eshell to stick β¦ I keep running back to vterm with my tail between my legs
eat fan here -- it doesn't require an additional external c library
mekeor: I need to try it out, I read on its README that vterm is faster but I'm not sure if I actually need that speed.
Eat seems to handle buffer resizes better
lispmacs[work]: I think an important point is to just use Eshell where you find it useful - same with all the other Emacs tools. Of course, you should explore some of Eshell's Emacs/Elisp integration features
The integrations with the rest of Emacs is probably what makes Eshell worth it once you get used to it. I am going to read up and try it out.
Thanks
einar_m: Thank you!
lounge-664: thanks chris good talk
chum-cha: This was fantastic, thanks lispmacs[work]!
mretka: M-x clap πππ
dubs: Great talk
[14:32:57] * gs-101 claps
lispmacs[work]: thank you
johnhamelink: Thank you
jsiegel62: Thanks!
lispmacs[work]: π
karthik: Thank you
mraabo: Very nice, thank you!
lounge-267: ty, lispmacs.
[14:33:42] * inkpotmonkey π
oylenshpeegul: π
ankit: Thank you, I've picked up a lot of things that I'll try to use in my workflow.
einar_m: Thank you for the inspiration, lismacs!
YouTube comments:
11:28 This should have been a shell-command instead of an eshell-command.
is the voice generated by a software program?
not judging by the no-pop-filter-noises
bro forgot he was giving a talk and thought he was narrating an audiobook lmao
be kind
Surprised you didn't mention "vterm" or "multi-vterm" especially if some shell commands have fancy ansi output.
I have a question regarding command line argument passing with emacsclient. In my fish.config file create a function called "e' so I can just type e sometext.txt
emacsclient -c "$argv[1]"
But I want this actually
emacsclient -c -a "" --eval "(set-frame-size (selected-frame) 106 42)" "$argv[1]"
so
$ e sometext.txt
That works but below doesn't work and I get an elisp message
If I use that emacsclient with --eval
$ e sometext.txt
says "nil"... and I don't get emacsclient to open up with the text file I want. It is very annoying and I guess once you put --eval you can't do argument passing but goes into an elisp mode I assume.
I think the scope of this talk was mentioned in the beginning.
Welcome to Emacs as a Shell, a talk by Christopher Howard forEmacs Conference 2024.In this talk, I would like to explore, or advocate for, aparticular perspective. I want to encourage people tothink of Emacs not as simply an editor or a developmentenvironment, but rather as a shell, or at least somethingthat allows us to do most of the things that we mightotherwise want to do from a shell.
What do I mean by shell? Byshell, I mean basically an interface that allows us tointeract with the rest of our system by entering commands.That definition is, perhaps, a little too broad, and so Iwill try to narrow it down with a list of features that,historically, we have come to expect from a shell. The Bashshell is one very portable and well-known shell, and formany of us it is maybe the prototypical example. But in thepast there have been many other shells, and there are othershells available today. If we are willing to be flexible inour thinking, we can think of Emacs as being a shell, or atleast providing most of the functionality that we expectfrom a shell.
Before further expanding on this idea, I must emphasizewhat I do not mean. First of all, I am not talking aboutrunning Bash, or some other external shell, from withinEmacs, although this is certainly possible. I am arguing,rather, for using Emacs as a shell, instead of other shells.Second, I do not mean running a terminal emulator fromwithin Emacs. Emacs has a built-in terminal emulator, butthis is not what I mean. A terminal emulator is essentially aprogram designed to control the cursor and text appearancein response to various control codes in order to mimic aterminal display device. There are certainly legitimatereasons to do this. Nevertheless, in general, it does notmake much sense to run a terminal emulator within Emacs,because Emacs has its own commands for controlling thecursor and text appearance. Also, due to the way Emacs wasdesigned historically, Emacs itself believes that it isrunning on a terminal. So you end up with layers upon layersof terminal emulation. Anyhow, at the end of the day, Emacswill not perform as well as a dedicated terminal emulatorprogram. I also think that, as we try to force ANSI terminalemulation into our Emacs workflow, this ultimately will bea hindrance to us in taking advantage of the natural andpleasant interfaces that are already available to uswithin Emacs. In brief, if your goal is simply to figure outhow to be able to do all your normal Bash command linewizardry from within an Emacs window instead of a GNOMEconsole window, you are headed down a different set of traintracks than I am. Also, something which I fear may confusethe issue for some viewers is the fact that Emacs ships withits own unique built-in shell, called the Emacs shell, orEshell.Eshell aims to be a legitimate shell, and provides a verysimilar experience to other shells like Bash, while beingwell integrated into the Emacs interface, and withoutgiving up the power of the Emacs Lisp engine. Eshell will bementioned multiple times in this talk. The entire talkcould, in fact, be about Eshell, except that I want the talkto cover all aspects of Emacs shell-like functionalitythrough its other tools, such as interactive commands andspecial modes. So, hopefully we can keep distinct in ourmind the ideas of Emacs as a shell versus the Emacs shell,though the latter is an important part of the former.
Let's get back to the fundamental idea of what is a shell. Inthe broadest definition, a shell is an interface whichallows you to interact with your operating system throughcommands. However, from a historical perspective, thereare a few basic capabilities which we expect to be part ofevery shell.First of all, the shell provides a means of launchingexternal programs. Some internal or built-in commandsmight also be made available. Second, the shell provides ameans of managing environment variables. In the past,environment variables often played a critical role as ameans of passing in options, file names, device names, andsuchlike to external programs. This is not quite as commontoday, but the environment still plays a critical role inmanaging things such as the path to executables andlibraries, as well as various other user, desktop, andsystem settings. The shell modifies the environment andpasses it on to external programs.Historically, job control was expected to be either afunction of the shell, or easily accessible from it.Usually today, our personal computing is notbatch-oriented. But typically, shells can run multipleprocesses simultaneously, as well as provide means tosuspend and terminate processes, which are usefulfeatures. Shells should be able to redirect and pipelineprocess input and output. This allows the user to connectprocess input and output with files, devices, or otherprocesses. Finally, shells are expected to have somelimited scripting capability, such as thePOSIX-compliant set of program statements andconditionals that Bash provides.As command-line wizards, there are a number of tasks weexpect to be able to do quickly and easily from our shell,even though these tasks are not the domain of the shellitself. A common task is file management and navigation. Wequickly navigate and manipulate the file system withstandard utilities that do things like change the currentworking directory, rename files, move files, and deletefiles. We usually expect to have access to some additionalprocess management utilities. These allow us to do thingssuch as find out the status of all processes running on thesystem, and send signals to processes. Finally, we expectto have access to some basic networking utilities. Forexample, we should be able to run commands that set upnetwork interfaces, ping computers, and download files.With a little reflection, we can see that Emacs can provideall or nearly all of the functionality we have described sofar. And the functionality can be called convenientlythrough one of several methods.Either a normal interactive call, like M-x something, or acall to an elisp function,or through Eshell commands, or through some special buffermode, such as the directory editor, which provides its owninterface to some functionality.It may be going too far to say that Emacs is a full replacementfor shells like Bash. Nevertheless, we can see that Emacscan do most of the things that we might otherwise do with ourshell.
Let us give some examples. First, can Emacs launchexternal commands? Of course. Now, there are somethinglike a half-dozen different ways to do that within Emacs, andsome are more convenient than others. From any Elispprogram, we can call functions like make-process andcall-process to launch external processes.These, however, generally are not convenient for quick,one-off commands. Another option would be to run Eshell,which would allow us to call the external program from afamiliar command line prompt.If we do not actually want to drop into Eshell just to run onecommand, we also have the interactive command,eshell-command,which would allow us to call the external program from afamiliar command line prompt.If we do not actually want to drop anEshell just to run one command, as I just mentioned, we alsohave the interactive command eshell-command, which allowsus to enter in a one-off command and run that immediately.And finally, there is also an interactive command calledsimply shell-command.Shell command is like Eshell command, but instead passesthe command off to our system shell, for example, bash.This is cheating, of course, but it might be useful or convenientin some scenarios.
Regarding environment variables, Emacs can read andmanipulate the environment variables, which in turn getpassed on to processes which it launches. Thegeneral-purpose interactive commands for this aregetenv and setenv. These commandsdeal with the one environment that is available throughoutall parts of your running Emacs session. In other words,these functions deal with a global environment, which isthe same wherever you are running getenv orsetenv.An important exception is that every instance of Eshellmaintains a distinct environment that will not be affectedby setenv calls run in other buffers. Also, Eshellhas some additional syntax for dealing with itsenvironment, including the set and export syntax.Regarding job control and process management, Emacs doesnot provide job control in the way that Bash users are usedto. We can, however, launch asynchronous processes, and dovarious things to them. From Eshell, or an eshell-commandcall, we can append the ampersand symbol to the command, andthis will cause the process to run asynchronously in adedicated buffer.Now, if the command is launched from Eshell, it will notactually run in a separate buffer, but the output will go tothe Eshell buffer.
We can run the interactive command list-processes to seeall the processes running for our current Emacs session.In Eshell, we can run the command "jobs" to get the same list.This will show the process name, process buffer name,process ID, and some other information. We can select theprocess buffer in the process list to bring up that processbuffer.We can also use the interactive command signal-process tosend any signal to a process, including "stop" to suspend theprocess, "continue" to resume the process, and "interrupt" orkill to terminate the process.
[00:17:00.180]Redirecting and pipelining input and output
Regarding redirecting and pipelining input and output,Eshell does support redirection similar to Bash, so you canoverwrite and append to files and some other objects. Inputredirection is not yet implemented, but it is on the Eshellto-do list. Eshell also has pipes. The default pipe, whichuses the familiar vertical bar symbol, pipes the databetween the commands using an intermediate Emacs buffer.This, while usually quite practical, is less efficientthan the system pipe. Therefore, Eshell also makesavailable a star-modified version, which uses the systempipe through a call to your system shell.So we can do things likedirect output to a file.We're unfortunately not able to do input redirection, butwe can use pipes.Elisp can manipulate and tie together processes in variousways, such as process filters and pipe processes, but Iwon't attempt to cover that. I feel like you should mentionagain that we have two kinds of pipes here available. So thispipe, the standard one, will pipe the data through Emacsbuffers. That's very practical in most cases, but it is lessefficient than piping through the system pipe. So Eshellmakes available another symbol for that, star, verticalbar, that allows you to explicitly use the system pipe.Regarding scripting: Of course, using Emacs makesavailable all the power of the Elisp API and third-partypackages, so we have that out of the gate. Eshell also hascontrol flow statements, like an "if" construct and a "for"construct. See the Eshell info manual, section 3.7, formore details.
And if you wish to write a script entirely in Eshell syntax,and store it in a separate file, this is possible with recentversions of Emacs.Here's an example of a brief script that I wrote.Unfortunately, an eshell mode for proper syntaxhighlighting is not yet available, but hopefully that willbe forthcoming. Note that Eshell syntax allows elispforms to be interspersed with regular command form foradditional scripting power. We will discuss this a littlemore later.
Regarding file system management. In Emacs, many of thecommon file system operations are available asinteractive commands. For example, M-x cd, to change yourbuffer's current working directory, and other M-x commandssuch as make-directorychmod,and delete-file. Of course, you can also drop into Eshell,or use M-x eshell-command to run the usual external commandsfor file system manipulation. Also, a file manager is builtinto Emacs, which can be run by calling M-x dired.The directory editor is powerful, but it is a bit strange tofolks expecting something like Midnight Commander or theGNOME file manager. It gives us a number of helpful featureslike the ability to mark files, and to run elisp functions onthem, and some other interesting ways to manipulate andrename the files. However, third-party Emacs extensionssuch as Midnight Commander Mode and Sunrise Commander areavailable to provide a Midnight Commander experience, for those whoprefer that sort of file management.Emacs also has the nifty TRAMP functionality built in,which allows you, most of the time, to easily edit files onother computers, as well as manipulate the file system.This transparently works through SSH and some otherprotocols that you can specify.
Regarding networking features, I don't have a lot ofinteresting things to say about this at the present, so I'llskip through this quickly. But if you do a little research,you will see that Emacs has a lot of functionality relatingto making network connections, interacting with the web,and such like, both built-in and in available packages, aswell as modes for doing things like Web browsing and Geminibrowsing. And of course, you can run the usual standardnetworking commands for your system through Eshell.
So having put forward the main arguments for this talk, Iwould like to take some time now to give a brief tour of a few ofthe features of Eshell, the Emacs shell. It bearsemphasizing that Eshell is not a drop-in replacement forBash, or even a Bash clone, though I believe the developersare trying to make much of the syntax very similar. Also,Eshell is not a terminal emulator, and it will not displaycorrectly applications which use advanced ANSI controlcodes. However, Eshell can be configured to be aware of suchapplications, and to run them automatically within theEmacs terminal emulator when launched. See section 5.1 ofthe Eshell manual titled Visual Commands.Though Eshell is not Bash, it has multiple features,pertaining mainly to its by-design Emacs integration,which may make it more appealing to use than Bash or anothershell.For one, Eshell allows entering commands on the commandline that are space and new line separated, withoutparentheses. Of course, all the other shells do this. Butwithin Eshell, it is possible to enter internal Emacsfunctions, as well as external commands.This allows us to do things like this.As far as I understand, it is possible to enter any Emacsfunction on the Eshell command line. However, some specialsyntax may be required if you are trying to pass in somethingthat is not a string or a number.As you might have noticed in the last example, Eshell makesit possible to use an Emacs buffer as a sink for output. Italso allows using a buffer as a source of input, though thisis slightly more complicated, since the buffer must beconverted to a string first. I have distilled this down intomy own function, named with the "at" symbol.And I will provide the brief snippet of code for this later.So to give an example, here's our messages buffer.And from Eshell, we can do something like this.Let's say here we wanted to grab our messages buffer to seeeverything that we had been loading during the startupprocess.So you can see how that could be very handy in a number ofscenarios.I wanted to briefly mention that we have a helpful functionhere called eshell-insert-buffer-name,which allows us to insert a buffer name into the currentbuffer at point using completion,which can save you a lot of typing.Another nice feature of Eshellis that it allows integrating ELisp into the command linecall. Let's give another example. Say we wanted to echo thedate to an event file or an event log.I should probably take a moment to explain this asteriskthat I'm occasionally using. So since Emacs, or excuse me,since Eshell can use internal or external Emacs, excuse me,internal Emacs commands or external commands, it maysometimes be necessary to clarify which one you want to use,since the names may overlap. Since my Eshell is configuredby default to prefer the internal Emacs functions, thensometimes I have to use the asterisk to specify that I wantthe external version.Here I can insert a bit of Elisp,and then redirect the output to the event log.Last, I want to mention that there are some optional Eshellmodules in Emacs, not turned on by default, which provideadditional nifty features.On my system, I have most of the optional modules turned on.An interesting module is eshell-smart, which does variousthings with cursor positioning and scrolling, so as to makeediting commands and reviewing output easier.Let's say I was to change directory to my boot directoryand use a command which involves lots of output.You'll notice right away that the cursor positioning is setsuch that I'm immediately able to view the top of the output.Also, I'm able to use the space bar to page through theoutput.So this is an opinionated feature, which assumes thatyou're likely going to want to review the outputimmediately, or that you often will. Of course, you canalways jump to the end.Also, after a command is entered, the cursor is immediatelyrepositioned to make it easy to edit the command.And also, if I don't want to edit the command, and I do not wantto review the output, I can simply start typing anothercommand.So that covers the brief tour of Eshell features.And that basically ends my talk.
However, a handful ofviewers might be wondering, is it possible to set Emacs to bemy login shell to completely replace bash in your loginexperience? The answer is yes, but in practice there arevarious difficulties involved which might make it notworth the trouble.Before doing this, you'll have to answer a few initialquestions. Do you want to make a new Emacs instance everytime you log in, or do you want it to connect to an Emacsserver? Which is popular among Emacs users, to reuse thesession, or to connect to the existing session. Also, do youwant a different result, whether in graphical or a terminalenvironment? And are you okay with your initializationfile being run every time you log in, including every new tabyou open in a terminal emulator? If we assume that you areusing a system with /etc/passwd user management, you getone field to specify the name of the shell program that youwant to use, and no arguments are allowed. So maybe you cansee how this might be challenging, depending on youranswers to the previous questions. You can work aroundthese issues in various ways, like modifying theauthentication system, or by specifying a script for yourlogin shell. But if your normal workflow is to simply log inand start Emacs and run that Emacs session until your nextreboot, then it probably isn't worth the bother.
So thank you for listening to my talk, Emacs as a Shell, byChristopher Howard for Emacs Conference 2024.At the bottom of this page, you can see a link to therepository containing the brief amount of code that wasfeatured here in this video, as well as a link to my personalGemini gemlog, as well as to a Web portal version of that.Thank you.