summaryrefslogtreecommitdiffstats
path: root/2022/captions/emacsconf-2022-eshell--top-10-reasons-why-you-should-be-using-eshell--howard-abrams--main.vtt
blob: 62b813f35ab9caa90944d8137905f3af2db844eb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
WEBVTT captioned by howard

NOTE Introduction

00:00:00.000 --> 00:00:04.999
I have 10 minutes to talk you into

00:00:05.000 --> 00:00:07.879
giving Eshell a second chance.

00:00:07.880 --> 00:00:10.119
Have the right perspective and expectation,

00:00:10.120 --> 00:00:12.919
and I think you’ll really enjoy it.

00:00:12.920 --> 00:00:15.679
Just remember eshell is a shell,

00:00:15.680 --> 00:00:17.839
not a terminal emulator.

00:00:17.840 --> 00:00:20.279
I use both Eshell and vterm.

00:00:20.280 --> 00:00:23.479
I’m going to talk and type fast,

00:00:23.480 --> 00:00:28.999
as I have 10 reasons for you to try Eshell again.

NOTE 1. It’s an Emacs REPL

00:00:29.000 --> 00:00:32.599
1. It’s an Emacs REPL.

00:00:32.600 --> 00:00:33.999
I mean, check this out.

00:00:34.000 --> 00:00:36.999
Let’s start up Eshell here.

00:00:37.000 --> 00:00:41.399
Let’s just type a Lisp expression.

00:00:41.400 --> 00:00:43.919
It works.

00:00:43.920 --> 00:00:48.599
As a shell, the parens are kinda optional.

NOTE 2. It’s also a shell

00:00:48.600 --> 00:00:52.519
2. It’s also a shell.

00:00:52.520 --> 00:00:56.479
While eshell may look like a shell, like Bash

00:00:56.480 --> 00:00:58.559
you should view it as a REPL

00:00:58.560 --> 00:01:02.399
with parenthesis-less s-expressions.

00:01:02.400 --> 00:01:05.559
This makes sense, because a shell command with options,

00:01:05.560 --> 00:01:07.999
like this ls command,

00:01:08.000 --> 00:01:10.119
looks like an s-expression.

NOTE 3. You can mix these two modes

00:01:10.120 --> 00:01:12.879
3. You can mix these two modes.

00:01:12.880 --> 00:01:14.959
Shells can call subshells

00:01:14.960 --> 00:01:17.919
which return their output like a function call,

00:01:17.920 --> 00:01:20.799
like this Bash command.

00:01:20.800 --> 00:01:22.759
In this Eshell example,

00:01:22.760 --> 00:01:24.639
I use the output of a text file

00:01:24.640 --> 00:01:27.959
as command line arguments to ripgrep.

00:01:27.960 --> 00:01:29.639
Notice how I use braces

00:01:29.640 --> 00:01:34.759
to state that it is a call to an eshell expression.

00:01:34.760 --> 00:01:40.039
We can mix Lisp-expressions and Shell-expressions.

00:01:40.040 --> 00:01:45.599
Allow me a contrived example.

00:01:45.600 --> 00:01:50.079
Notice I use good ol' setq to create a variable.

00:01:50.080 --> 00:01:54.919
Yes, those are global Emacs variables available everywhere.

00:01:54.920 --> 00:01:59.599
In Eshell, the wildcard actually creates a list.

00:01:59.600 --> 00:02:04.479
This variable assignment doesn’t work as you might expect,

00:02:04.480 --> 00:02:07.559
as setq in Eshell is still setq,

00:02:07.560 --> 00:02:10.319
and it assigns variables in pairs.

00:02:10.320 --> 00:02:17.119
To make a list in Eshell, we use listify:

00:02:17.120 --> 00:02:21.239
Without parens, Eshell is in “shell mode”,

00:02:21.240 --> 00:02:23.799
which means that words are strings,

00:02:23.800 --> 00:02:26.879
and variables need to be prefixed with dollar signs.

00:02:26.880 --> 00:02:32.399
A command can have both Eshell and Lisp expressions.

00:02:32.400 --> 00:02:34.559
As you can see here,

00:02:34.560 --> 00:02:37.119
I have a call to ripgrep,

00:02:37.120 --> 00:02:40.319
but part of it is an s-expression.

00:02:40.320 --> 00:02:42.239
Remember the differences:

00:02:42.240 --> 00:02:46.159
With parens, eshell treats it as Lisp,

00:02:46.160 --> 00:02:49.199
like the last line in my example.

00:02:49.200 --> 00:02:53.919
With braces, eshell follows these shell-like rules:

00:02:53.920 --> 00:02:57.159
First, if it looks like a number, it's a number.

00:02:57.160 --> 00:02:59.439
Otherwise, eshell converts it to a string

00:02:59.440 --> 00:03:03.679
(quotes, like a shell, groups words).

00:03:03.680 --> 00:03:07.519
What about this mix between functions and executables

00:03:07.520 --> 00:03:10.839
for the first word?

00:03:10.840 --> 00:03:15.439
Functions that begin with eshell are called first.

00:03:15.440 --> 00:03:19.079
Next in priority are executables on your $PATH,

00:03:19.080 --> 00:03:22.159
then matching Lisp functions.

00:03:22.160 --> 00:03:23.940
You can actually switch this order

00:03:23.941 --> 00:03:27.559
with the `eshell-prefer-lisp-functions` variable.

NOTE 4. Emacs is better than shell

00:03:27.560 --> 00:03:31.759
4. Emacs is actually better than shell.

00:03:31.760 --> 00:03:35.199
If the following works, why would you call

00:03:35.200 --> 00:03:40.039
expr or bc or dc, or any of those other calculators?

00:03:40.040 --> 00:03:43.639
You can just call a Lisp expression.

00:03:43.640 --> 00:03:47.999
Why call less or more when you could call view-file?

00:03:48.000 --> 00:03:52.839
Here, I’ve aliased less to view-file.

00:03:52.840 --> 00:03:57.559
Load it up, and it shows up in an Emacs mode.

00:03:57.560 --> 00:04:01.519
Just like with less, if you hit q,

00:04:01.520 --> 00:04:05.759
you go back to your Eshell terminal.

00:04:05.760 --> 00:04:08.439
I do have an improvement, though.

00:04:08.440 --> 00:04:10.479
The problem with view-file is

00:04:10.480 --> 00:04:13.399
it takes a single file as an argument.

00:04:13.400 --> 00:04:15.719
In a shell, we might want to view more than one.

00:04:15.720 --> 00:04:18.719
So let’s make a solution to that.

00:04:18.720 --> 00:04:20.999
This function will call the first function

00:04:21.000 --> 00:04:22.159
with the first argument,

00:04:22.160 --> 00:04:26.679
and the second function with each of the rest.

00:04:26.680 --> 00:04:29.559
This allows me to make a version of less

00:04:29.560 --> 00:04:33.159
that calls view-file on the first [argument] given,

00:04:33.160 --> 00:04:36.079
but open in another window for each additional file.

NOTE 5. Better regular expressions

00:04:36.080 --> 00:04:41.239
5. Better regular expressions.

00:04:41.240 --> 00:04:44.799
Can’t remember regular expressions when calling

00:04:44.800 --> 00:04:48.639
grep or some other search function? Use the rx macro.

00:04:48.640 --> 00:04:55.919
Here I call ripgrep again, but this time,

00:04:55.920 --> 00:05:00.679
I’m using a Lisp expression calling the rx macro

00:05:00.680 --> 00:05:04.719
to look for UUIDs in the files in my current directory.

00:05:04.720 --> 00:05:08.159
But I have another improvement for this.

00:05:08.160 --> 00:05:13.479
While the rx macro is freaking cool for Emacs Lisp,

00:05:13.480 --> 00:05:15.919
it doesn’t always translate to regular expressions

00:05:15.920 --> 00:05:20.079
accepted by most commands.

00:05:20.080 --> 00:05:25.199
The (I have no idea how to pronounce this) pcre2el project

00:05:25.200 --> 00:05:28.519
can convert from a Lisp regular expression

00:05:28.520 --> 00:05:31.359
to Perl-compatible regular expressions (PCRE)

00:05:31.360 --> 00:05:33.519
acceptable by most search commands.

00:05:33.520 --> 00:05:37.879
I’ve created a new macro here, prx,

00:05:37.880 --> 00:05:41.319
that translates the output of the rx macro.

00:05:41.320 --> 00:05:46.519
This allows me to type something much more readable,

00:05:46.520 --> 00:05:48.519
and probably easier to remember.

00:05:48.520 --> 00:05:54.679
Certainly easier than this freaking regular expression.

00:05:54.680 --> 00:05:59.439
I’ve got an even better improvement.

00:05:59.440 --> 00:06:03.559
The rx macro with regular expression snippets

00:06:03.560 --> 00:06:05.759
can be assigned to key words

00:06:05.760 --> 00:06:08.679
that I can then take advantage of.

00:06:08.680 --> 00:06:13.479
Now our command would be much simpler to type.

NOTE 6. Loops are better with predicates

00:06:13.480 --> 00:06:16.159
6. Loops are better with predicates.

00:06:16.160 --> 00:06:18.759
Let’s say you want to remove the execute bit

00:06:18.760 --> 00:06:20.479
from files that have it.

00:06:20.480 --> 00:06:24.399
In a shell like bash, you need both a for loop and an if,

00:06:24.400 --> 00:06:26.599
as you can see in this example.

00:06:26.600 --> 00:06:31.559
With eshell, use a predicate to combine into a simple loop.

00:06:31.560 --> 00:06:34.359
The paren x after a file glob

00:06:34.360 --> 00:06:36.879
filters for only files marked as executable.

00:06:36.880 --> 00:06:43.559
Now here is another improvement.

00:06:43.560 --> 00:06:47.959
Since we often type loops to execute on one command,

00:06:47.960 --> 00:06:49.519
what about creating a function

00:06:49.520 --> 00:06:50.999
that can do this all in one go?

00:06:51.000 --> 00:06:57.599
This do function splits the arguments on that double colon,

00:06:57.600 --> 00:07:00.079
where the left side is a single statement to run,

00:07:00.080 --> 00:07:02.599
and the right side is a list of files.

00:07:02.600 --> 00:07:05.839
I have to append and flatten it

00:07:05.840 --> 00:07:07.639
in order for it to work.

00:07:07.640 --> 00:07:09.399
It loops through each file,

00:07:09.400 --> 00:07:12.079
creating an eshell command with the file appended.

00:07:12.080 --> 00:07:15.759
With this, I can remove the execute bit

00:07:15.760 --> 00:07:20.759
on all CSV files that have it.

00:07:20.760 --> 00:07:24.319
I see that my example wasn’t too good, as most commands

00:07:24.320 --> 00:07:29.039
like chmod accept multiple files, but you get the idea.

00:07:29.040 --> 00:07:33.159
In my final, larger form on my website,

00:07:33.160 --> 00:07:35.279
I don’t assume the command expression accepts

00:07:35.280 --> 00:07:36.719
a file as a final argument,

00:07:36.720 --> 00:07:39.639
as I can also replace underscores with the filename.

NOTE 7. Output of last command

00:07:39.640 --> 00:07:45.399
7. Output of last command.

00:07:45.400 --> 00:07:48.799
Most shells have a special variable

00:07:48.800 --> 00:07:52.839
like $? for the exit code of the last command.

00:07:52.840 --> 00:07:55.919
While reading through the source code,

00:07:55.920 --> 00:07:58.799
I noticed that the $$ refers to

00:07:58.800 --> 00:08:00.599
the output of the last command.

00:08:00.600 --> 00:08:05.799
This seems pretty cool.

00:08:05.800 --> 00:08:10.759
However, Eshell returns true or nil

00:08:10.760 --> 00:08:12.719
when running external commands,

00:08:12.720 --> 00:08:15.879
so accessing the output from a call to ls

00:08:15.880 --> 00:08:19.479
doesn’t work as expected.

00:08:19.480 --> 00:08:21.119
But this is Emacs.

00:08:21.120 --> 00:08:23.159
We can fix that.

00:08:23.160 --> 00:08:28.119
After running any command, eshell sets these four variables.

00:08:28.120 --> 00:08:33.519
I can hook a function call after every Eshell command.

00:08:33.520 --> 00:08:36.759
Using buffer-substring,

00:08:36.760 --> 00:08:39.279
I store the output into a global variable,

00:08:39.280 --> 00:08:43.599
and extend Eshell’s special variables list.

00:08:43.600 --> 00:08:46.519
In my Emacs configuration,

00:08:46.520 --> 00:08:48.479
I turned this variable into a ring,

00:08:48.480 --> 00:08:51.439
so while $$ works,

00:08:51.440 --> 00:08:54.399
so does array sub-scripting on that variable.

00:08:54.400 --> 00:08:58.399
This allows me to run a command

00:08:58.400 --> 00:09:02.279
and use the output from that command more than once.

00:09:02.280 --> 00:09:05.279
The code for this is a bit longer,

00:09:05.280 --> 00:09:08.519
so you’ll need to see my Emacs configuration for details.

NOTE 8. Redirection back to Emacs

00:09:08.520 --> 00:09:13.439
8. Redirection back to Emacs.

00:09:13.440 --> 00:09:14.879
Output of any command

00:09:14.880 --> 00:09:18.519
can go to kill-ring (or the clipboard).

00:09:18.520 --> 00:09:21.079
Think of the implications.

00:09:21.080 --> 00:09:23.839
You don’t have to go into text selection mode.

00:09:23.840 --> 00:09:26.239
Just grab the output.

00:09:26.240 --> 00:09:30.279
In fact, with our $$ improvement,

00:09:30.280 --> 00:09:33.239
we can always copy the output from the last command

00:09:33.240 --> 00:09:34.079
to the clipboard.

00:09:34.080 --> 00:09:37.999
Better yet, let’s write the output

00:09:38.000 --> 00:09:39.399
to our engineering notebook.

00:09:39.400 --> 00:09:41.679
Here’s my idea.

00:09:41.680 --> 00:09:46.079
First, create a capture template that takes a string,

00:09:46.080 --> 00:09:48.199
or if called interactively, the region,

00:09:48.200 --> 00:09:51.879
and that does an immediate-finish after inserting

00:09:51.880 --> 00:09:53.879
that string to the default notes file.

00:09:53.880 --> 00:09:57.679
Next, create a wrapper function

00:09:57.680 --> 00:10:01.559
to call org-capture-string to run that template.

00:10:01.560 --> 00:10:07.639
Finally, we add our new function to eshell-virtual-targets.

00:10:07.640 --> 00:10:08.759
Let’s see this in action.

00:10:08.760 --> 00:10:15.707
I have a CSV file of user information.

00:10:15.708 --> 00:10:19.719
I can use grep and cut to extract some of that

00:10:19.720 --> 00:10:26.879
and write it out to this month’s engineering notebook.

NOTE 9. Using Emacs buffers

00:10:26.880 --> 00:10:35.279
9. Using Emacs buffers.

00:10:35.280 --> 00:10:39.159
Why leave the results of eshell commands

00:10:39.160 --> 00:10:40.279
in the *eshell* buffer?

00:10:40.280 --> 00:10:44.119
Send the output into a buffer where you can use it.

00:10:44.120 --> 00:10:47.999
Here’s a call to ripgrep

00:10:48.000 --> 00:10:50.759
that searches for lines with email addresses

00:10:50.760 --> 00:10:53.519
using a complicated regular expression

00:10:53.520 --> 00:10:56.079
that I added to my prx macro.

00:10:56.080 --> 00:11:01.079
When I switch to this almost-grep buffer,

00:11:01.080 --> 00:11:03.319
I can turn on grep-mode.

00:11:03.320 --> 00:11:09.039
Now I can jump around as if I just called grep directly.

00:11:09.040 --> 00:11:14.759
Perhaps I’m proficient with my prx macro

00:11:14.760 --> 00:11:16.639
to filter out entries,

00:11:16.640 --> 00:11:19.279
but not good with shell commands

00:11:19.280 --> 00:11:23.999
that I can use in pipes to extract just one…

00:11:24.000 --> 00:11:26.039
the address column, for instance?

00:11:26.040 --> 00:11:28.959
Let’s just extract it,

00:11:28.960 --> 00:11:33.279
send it to a buffer called email-list,

00:11:33.280 --> 00:11:38.479
and now I can use Emacs commands that I know and love

00:11:38.480 --> 00:11:39.799
to edit the data directly.

00:11:39.800 --> 00:11:55.799
We currently have an over-sight

00:11:55.800 --> 00:11:58.839
that the Eshell’s built-in cat command

00:11:58.840 --> 00:12:02.719
doesn’t pipe buffer contents as standard in.

00:12:02.720 --> 00:12:07.919
So I created a bcat, a buffer cat, function to do this.

00:12:07.920 --> 00:12:09.879
So this command works

00:12:09.880 --> 00:12:14.599
to grab my email addresses I just extracted

00:12:14.600 --> 00:12:16.319
and send them to another program.

00:12:16.320 --> 00:12:20.959
If you’re interested, I have a more elaborate

00:12:20.960 --> 00:12:25.759
and yet simpler workflow surrounding sending data

00:12:25.760 --> 00:12:28.399
back and forth from Eshell to Emacs buffers.

NOTE 10. cd to remote systems

00:12:28.400 --> 00:12:35.679
10. Did I mention that you can cd to remote systems?

00:12:35.680 --> 00:12:39.879
This command uses SSH to jump to my host, goblin,

00:12:39.880 --> 00:12:44.039
start a root session, and jump to the etc directory.

00:12:44.040 --> 00:12:47.719
Remember that Tramp can be finicky

00:12:47.720 --> 00:12:52.839
if you start blinging your remote hosts with oh-my-zshell,

00:12:52.840 --> 00:12:57.790
and funky prompts and things like that,

00:12:57.791 --> 00:12:59.359
so your mileage may vary.

NOTE Summary

00:12:59.360 --> 00:13:03.959
In summary: Use eshell if you want

00:13:03.960 --> 00:13:07.319
a quick way to run commands and Emacs functions as a REPL,

00:13:07.320 --> 00:13:11.479
or to run an OS program but process the output with Emacs.

00:13:11.480 --> 00:13:15.919
Keep in mind that Eshell has two types of subshells,

00:13:15.920 --> 00:13:19.599
and you can mix and match during a command call.

00:13:19.600 --> 00:13:22.639
The rx macro is really cool.

00:13:22.640 --> 00:13:26.599
Eshell loops are better with filters and predicates …

00:13:26.600 --> 00:13:28.239
if you can remember them.

00:13:28.240 --> 00:13:30.959
Take advantage of Emacs buffers

00:13:30.960 --> 00:13:32.879
to really enhance your shell experience.

00:13:32.880 --> 00:13:36.039
You’ve now seen that just like Emacs,

00:13:36.040 --> 00:13:39.519
I’ve crafted Eshell to be my own shell creation,

00:13:39.520 --> 00:13:41.039
tailored to my workflow.

00:13:41.040 --> 00:13:44.799
So, steal my spells, cast your own magic,

00:13:44.800 --> 00:13:48.759
but feel free to share your incantations back to me.

00:13:48.760 --> 00:13:51.359
I’ve gone over my time allotment, so we’ll have to

00:13:51.360 --> 00:13:53.679
continue this discussion on the intertubes.

00:13:53.680 --> 00:13:57.159
Why yes, I have joined the birdless diaspora,

00:13:57.160 --> 00:13:59.199
so toot me over there.

00:13:59.200 --> 00:14:01.920
Thanks.