Shell Tricks That Make Life Easier (and Save Your Sanity)

https://blog.hofstede.it/shell-tricks-that-actually-make-life-easier-and-save-your-sanity/

Comments

alberto-mMar 26, 2026, 12:34 PM
One thing I find life-changing is to remap the up arrow so that it does not iterates through all commands, but only those starting with the characters I have already written. So e.g. I can type `tar -`, then the up arrow, and get the tar parameters that worked last time.

In zsh this is configured with

    bindkey "^[OA" up-line-or-beginning-search # Up
    bindkey "^[OB" down-line-or-beginning-search # Down
bwhaleyMar 26, 2026, 12:57 PM
Once you start using CTRL+r, you may find that you never reach for up arrow again.
pavel_lishinMar 26, 2026, 1:59 PM
I'm familiar with ctrl-r, but I still very much like the up-arrow behavior described by that commenter.
dotancohenMar 26, 2026, 10:38 PM
What I love about the default Bash Crtl-C behaviour is that once a command has been located, the bash history is moved to the history of that command, until Enter is pressed.

  $ a
  bash: a: command not found
  $ b
  bash: b: command not found
  $ c
  bash: c: command not found
  $ d
  bash: d: command not found
  $ <CTRL-R> b <UP>
  $ a
That's great if I don't remember which command I was experimenting with, but I do know other commands that I did around that time (usually a file that I edited with VIM).
flirMar 26, 2026, 3:42 PM
Looking at it from a "law of least surprise" angle, it's exactly how it should behave.

"I typed 'cd di↑' and you're giving me 'pwd'??"

ZetaphorMar 26, 2026, 11:35 PM
Atuin[1] feels like the best of both worlds to me.

[1] https://github.com/atuinsh/atuin

annie511266728Mar 27, 2026, 6:31 AM
Atuin looks pretty nice — I might give it a try.

I went down the “fully automatic history” path before, but it mostly turned into noise for me.

Keeping a tiny cheatsheet of things I had to look up twice ended up working better.

BeetleBMar 26, 2026, 3:07 PM
There is a difference, I believe. Doesn't Ctrl+r do a substring search instead?
imglorpMar 26, 2026, 4:54 PM
Yes it's different: it will match anywhere in the previous command lines.
kuschkufanMar 26, 2026, 1:10 PM
And once you want to one-up this look into fzf.
nidnoggMar 26, 2026, 1:31 PM
And once you get tired of fzf and want something better, you reach for https://atuin.sh.

Completely transformed all of my workflows

seedieMar 26, 2026, 2:32 PM
From the atuin.sh website

> Sync your shell history to all of your machines

I think of my shell history as very machine specific. Can you give some insights on how you benefit from history sync? If you use it.

CyphusMar 26, 2026, 2:41 PM
That feature is entirely optional and disabled by default. Atuin stores your shell history locally in a sqlite db regardless of whether you choose to sync it. I thought fzf was fast, but atuin makes it look slow by comparison.
foobarianMar 26, 2026, 2:45 PM
Same, I find shared history not very useful.

However what I do find useful is eternal history. It's doable with some .bashrc hacks, and slow because it's file based on every command, but:

- never delete history

- associate history with a session token

- set separate tokens in each screen, tmux, whatever session

- sort such that backward search (ctrl-R) hits current session history first, and the rest second

Like half my corporate brain is in a 11M history file at this point, going back years.

What I would love is to integrate this into the shell better so it's using sqlite or similar so it doesn't feel "sluggish." But even now the pain is worth the prize.

commandersakiMar 26, 2026, 4:39 PM
I just want to give a perspective of someone that uses the 'eternal history' in bash per Eli Bandersky [1] and reluctance to use something like atuin (without/ignoring shared history).

First, as for speed and responsiveness, if there is a degradation, it is imperceptible to me. I wouldn't have a clue that my interactive shell is slowing down because it is logging a command to ~/.persistent_history.

My persistent_history is 4MB and has been migrated from machine to machine as I've upgraded, it's never felt slow to edit with (neo)vim or search with system supplied grep.

Eli's way of doing it also includes the timestamps for all commands, so it's easy to trace back when I had run the command, and duplicates are suppressed. In fact my longest persistent_history goes back to 2019-07-04, so I've been using it for quite some time now.

But the larger point I wanted to make is that I wouldn't feel comfortable switching this, in my opinion, quite efficient setup to displace it with an sqlite database. That would require a special tool to drill through the history and search rendering simple unix utilities useless. As Eli suggested, if your history gets too big, simply rotate the file and carry on. I have the alias phgrep to grep ~/.persistent_history, but I can easily have another alias to grep ~/.persistent_history*.

[1]: https://eli.thegreenplace.net/2013/06/11/keeping-persistent-...

fragmedeMar 26, 2026, 4:15 PM
You don't have to setup shared history with Atuin if you don't want to and that's what's holding you back. Otherwise it hits the rest of your requirements. Just don't hesitate to change from the default config.
__MatrixMan__Mar 26, 2026, 6:56 PM
1. work on a project on host_foo in /home/user/src/myproject

2. clone it on host_bar in /home/user/src/myproject

If you set filter_mode = "directory", you can recall project specific commands from host_foo for use on host_bar even though you're working on different machines and the search space won't be cluttered with project specific commands for other projects.

doubled112Mar 26, 2026, 11:13 PM
I sync Atuin to my home server but I also configure it to be host specific by default.
twelvedogsMar 26, 2026, 11:17 PM
If you use multiple terminals it kinda sucks unless you do export PROMPT_COMMAND='history -a' in your.bashrc or something cause only the last closed terminal saves to history
soraminazukiMar 26, 2026, 5:34 PM
Prefix search is faster for the majority of cases. CTRL-r / FZF is useful for the remaining ones.
noisy_boyMar 26, 2026, 3:38 PM
export EDITOR=vi and then hitting Esc puts you into vi mode; k, j to move up/down through history or pressing / to search etc including using regex is all available.
antonvsMar 27, 2026, 5:50 AM
Ctrl-r can’t replace prefix search.
sureglymopMar 26, 2026, 4:32 PM
I agree it's a game changer! For bash to do the same I put this in my .inputrc:

    ## arrow up
    "\e[A":history-search-backward
    ## arrow down
    "\e[B":history-search-forward
hebelehubeleMar 26, 2026, 3:58 PM
This is the default `fish` shell behavior. Type anything, up/down keys to iterate through full commands that containing the term; alt + up/down to iterate through args containing the term.
naikrovekMar 26, 2026, 9:05 PM
Fish is underrated
moebrowneMar 26, 2026, 1:23 PM
This can also be achieved with `.inputrc`:

    "\e[A": history-search-backward
    "\e[B": history-search-forward
az09mugenMar 26, 2026, 9:45 PM
Thank you !
dkgaMar 27, 2026, 6:06 AM
Very nice! Here's the full code for those that had, like me, a more minimalistic .zshrc:

```

autoload -U up-line-or-beginning-search

autoload -U down-line-or-beginning-search

zle -N up-line-or-beginning-search

zle -N down-line-or-beginning-search

bindkey "^[[A" up-line-or-beginning-search

bindkey "^[[OA" up-line-or-beginning-search

bindkey "^[[B" down-line-or-beginning-search

bindkey "^[[OB" down-line-or-beginning-search

```

zahlmanMar 27, 2026, 1:24 AM
I'd try this, but I often find that I want to repeat a cycle of two or more commands. Yes, I probably should edit and put them on one line with semicolons (or even make a function), but.
henrik_wMar 27, 2026, 10:07 AM
Or put && between them - I had "compile;run" and when compile failed, it still ran (but the old build). Took me a while to figure out. && ensures the first command succeeds. Anyway, so worth it to combine commands into one line for easy re-run.
BeetleBMar 26, 2026, 3:07 PM
Heh. I've done this since forever, but I use PgUp and PgDn so I can retain the original meaning of the up arrow key.
dsp_personMar 26, 2026, 4:09 PM
When I was on ubuntu it was easy to uncomment a couple lines in /etc/inputrc for this
FishkinsMar 26, 2026, 5:05 PM
I do something similar. I leave up and down arrows alone, but have ctrl+p and ctrl+n behave as you describe.
n8henrieMar 26, 2026, 12:59 PM
Did this many years ago (but with bash) -- life changing is an apt way of saying it.
account42Mar 26, 2026, 1:19 PM
Here's the Bash commands for this in case anyone is looking for them

  bind '"\e[A"':history-search-backward
  bind '"\e[B"':history-search-forward
heresie-dabordMar 26, 2026, 12:41 PM
> life-changing

For further life-changing experience... add aliases to .bash_aliases

    alias gph='history | grep --colour -i '
    alias gpc='grep --colour -Hin '
    #if gnu time is installed
    alias timef='/usr/bin/time -f "tm %E , cpu %P , mem %M" '
TacticalCoderMar 26, 2026, 3:09 PM
I've got many like these I copied from various people over the years.

One I came up and that I use all the time:

    alias wl='wc -l'
I use it so much I sometimes forget it's not stock.
naikrovekMar 26, 2026, 7:58 PM
Atuin is better than anything I’ve used in a shell.
TacticalCoderMar 26, 2026, 3:07 PM
That's a nice one.

One thing I do is configure my keyboard so that "modifier+{ijkl}" mimicks the inverted T arrows key cluster. So there's never a need for me to reach for the arrow keys. And {ijk} makes more sense than vi's {hjkl} and is faster/more logical/less key fingers travel. The nice thing is: as I do this at the keyboard level, this works in every single map. "modifier" in my case is "an easily reachable key in a natural hand position on which my left thumb is always resting" but YMMV.

I set that up years ago and it works in every app: it's gorgeous. Heck, I'm using it while editing this very message for example.

And of course it composes with SHIFT too: it's basically arrow keys, except at the fingers' natural positions.

ahmedfromtunisMar 26, 2026, 9:18 AM
Using the terminal becomes much more cozy and comfortable after I activate vim-mode.

A mistake 3 words earlier? No problem: <esc>3bcw and I'm good to go.

Want to delete the whole thing? Even easier: <esc>cc

I can even use <esc>v to open the command inside a fully-fledged (neo)vim instance for more complex rework.

If you use (neo)vim already, this is the best way to go as there are no new shortcuts to learn and memorize.

piekvorstMar 26, 2026, 11:18 AM
This reminds me of an excerpt from an old Emacs manual:

    . . . if you forget which commands deal with windows, just type @b[ESC-?]@t[window]@b[ESC].
This weird command is presented with such a benevolent innocence as if it's the simplest thing in the world.

I think the better advice for command-line editing would be to set up the mouse.

mikkupikkuMar 26, 2026, 6:08 PM
I have yet to see a shell that has mouse enabled line editing support. It should certainly be possible though.

I do prefer vi bindings at the same time though. Vi bindings and mouse support complement each other well, you don't have to choose one or the other, just use whichever feels most natural and convenient in that exact moment.

piekvorstMar 27, 2026, 12:42 PM
I think modern terminal emulators and readline-based shells support it.

This is not to say that there's nothing to improve. Multiline editing experience suffers, and non-readline shells aren't supported. Those problems were solved by Plan 9 (at the cost of dropping xterm compatibility), but the mainstream hasn't yet adopted those solutions.

Ferret7446Mar 27, 2026, 2:30 AM
I think you're confused by the markup. It looks like it's saying Alt-? (Alt and Esc are interchangeable due to terminal reasons) to open up the help search and then type 'window' to search for window commands. Sounds pretty simple to me
piekvorstMar 27, 2026, 12:22 PM
Indeed, @b[] is for bold, and @t[] is for something else. The joke falls apart, and somehow a piece of my identity goes with it. But thanks for clarifying.
gbaconMar 26, 2026, 10:01 PM
For a bit about the language, read `3bcw` as move `b`ackward by `3` words and `c`hange the `w`ord under the cursor.

The general form of `b` is `[count]b` where

    [count] An optional number that may precede the command to multiply
            or iterate the command.  If no number is given, a count of one    
            is used, unless otherwise noted.  Note that in this manual the
            [count] is not mentioned in the description of the command,
            but only in the explanation.  This was done to make the
            commands easier to look up.  If the 'showcmd' option is on,
            the (partially) entered count is shown at the bottom of the
            window.  You can use <Del> to erase the last digit (|N<Del>|).

    b       [count] words backward.  |exclusive| motion.
https://vimdoc.sourceforge.net/htmldoc/intro.html#[count]

https://vimdoc.sourceforge.net/htmldoc/motion.html#b

For `c` it’s

    ["x]c{motion} Delete {motion} text [into register x] and start
                  insert.  When  'cpoptions' includes the 'E' flag and
                  there is no text to delete (e.g., with "cTx" when the
                  cursor is just after an 'x'), an error occurs and
                  insert mode does not start (this is Vi compatible).
                  When  'cpoptions' does not include the 'E' flag, the
                  "c" command always starts insert mode, even if there
                  is no text to delete.

    {motion} A command that moves the cursor.  These are explained in
             |motion.txt|.  Examples:
                 w           to start of next word
                 b           to begin of current word
                 4j          four lines down
                 /The<CR>    to next occurrence of "The"
https://vimdoc.sourceforge.net/htmldoc/change.html#c

https://vimdoc.sourceforge.net/htmldoc/intro.html#{motion}

JadeNBMar 26, 2026, 1:42 PM
> This weird command is presented with such a benevolent innocence as if it's the simplest thing in the world.

I think it's a question of context and familiarity. To a vim user, like me and, I assume, ahmedfromtunis, their examples do indeed seem simple and natural. Presumably, to an emacs user, the example you quote (if it's quoted literally—I don't use emacs and can't even tell) is just as natural, and assuming some comfort with emacs is presumably OK in a manual for the software!

OryginMar 26, 2026, 2:23 PM
> assuming some comfort with emacs is presumably OK in a manual for the software!

How do you get familiar with the software, if the manual expects you to be an expert in it already?

noisy_boyMar 26, 2026, 3:42 PM
I got familiar with vi by reading a book that had the main vi commands listed out. First learnt how to quit without saving changes, the rest was just practice.
umanwizardMar 26, 2026, 2:52 PM
Not sure if it did at the time, but today emacs comes with a tutorial. You’re not expected to learn it by starting on page 1 of the manual.
OryginMar 26, 2026, 3:57 PM
Why not? I expect to learn how to use a software by reading its manual.
umanwizardMar 26, 2026, 4:37 PM
Surely you can still do that, but starting with the tutorial will be easier and more efficient.
Pay08Mar 26, 2026, 2:57 PM
By reading introductory material.
matthew-craigMar 26, 2026, 4:08 PM
The example confusingly includes some weird markup. It's just saying press `ESC-?` then type "window" to search for window commands. These isn't even valid in modern Emacs. The equivalent is `C-h` followed by `a` then type "window".
commandersakiMar 26, 2026, 10:07 AM
I've been a (n)vim user for 20+ years now, but I hate vi-mode in the shell. However if I feel that I need to do a complex command, I just do ctrl-x+e to open up in neovim (with EDITOR=nvim set). I find it a good middle ground.
void-starMar 26, 2026, 1:43 PM
It’s strange. I have heard this from lots of others too. I think I am an anomaly here. I can’t live without shell vi mode
fp64Mar 26, 2026, 3:36 PM
You're not alone, I heavily rely on vi mode and often struggle if I'm on someone else's machine and can't use it. I always wonder how you're supposed to work without it but I never dare to ask
Linux-FanMar 26, 2026, 5:09 PM
`set -o vi` is quickly typed in anger...
dbacarMar 26, 2026, 7:58 PM
it is an additional burden to switch to shell vi mode, it is not the standard. Maybe you can put it in all of yout bashrc files but you will probably hear some swearing from the people logging to your machines :).
lenkiteMar 26, 2026, 6:40 PM
Same - shell vi mode is critical for intensive terminal sessions.
busfahrerMar 26, 2026, 1:11 PM
I'm the same and in my opinion this is the best of both worlds. Taking the time to learn some of the regular (emacs-style) shortcuts is one of the best investments I've ever done. Even just CTRL+Y and the likes.

edit: And of course, CTRL+R, the best time saver of all

looshchMar 26, 2026, 9:08 PM
agreed, i use neovim as a terminal multiplexer because vi-mode is really bad. I wrote a blog post on how i solved the issue for myself https://loosh.ch/blog/neovidenal
xtiansimonMar 26, 2026, 11:43 AM
Huh. I don’t use vi-mode for more than jumping to the beginning or end of a line, which I like a lot.
wbrdMar 26, 2026, 12:32 PM
I'm a vim user but in the shell I use Ctrl-a and Ctrl-e to get to the beginning and end. If I need more editing I use Ctrl-x Ctrl-e to hop into vim.
void-starMar 26, 2026, 2:42 PM
It really shines for navigating history. <esc>/ searches history the same way as the editor search function
umanwizardMar 26, 2026, 2:53 PM
C-a and C-e are your friend.
irishcoffeeMar 26, 2026, 11:55 AM
You mean, like the “home” and “end” buttons?
wholinator2Mar 26, 2026, 12:59 PM
Yeah but those are so far away, i have to hunt for them every time
sudonemMar 26, 2026, 10:39 AM
Agree.

I WANT to love it - and if I was only ever working on one, or a small number of systems that I was the only one working on I’d probably do it. I’m ALL about customizing my environment.

However ssh into various servers through the day (some of which are totally ephemeral), and having to code switch my brain back and forth between vim mode and emacs mode in the shell would just slow me down and be infuriating each time I connect to a new box.

helterskelterMar 26, 2026, 5:18 PM
I used to hate it because I'd sometimes change modes without realizing it, but I began to appreciate it a lot more when I added a mode indicator -- a red 'N' on the rightmost side of the input line.
dbtcMar 26, 2026, 4:42 PM
I use vim a lot but not on the shell

A mistake 3 words earlier?

meta-bbbd (not as elegant, I admit)

delete the whole thing?

ctrl-ak (this is even quicker than vim, especially if capslock is mapped to ctrl)

the control-based emacs movements work system-wide on macos btw. I am using ctrl-p and ctrl-n to go up and down lines, ctrl-a and ctrl-e to go to beginning and end of lines while writing this comment in by browser (which has vimium extension)

Sometimes I wish vim just had full emacs bindings while in insert mode. But I don't like to mess with defaults too much.

I keep thinking I should give vim readline a try though, so maybe today. Thanks for the comment.

sanjayjcMar 27, 2026, 4:53 AM
> "delete the whole thing?"

With vi (after running "set -o vi"): <esc>kC

(k to move up back one position in history. C to "change" to the end of the line.)

This is equivalent to doing the following with "set -o emacs": <ctrl>pu

Regardless, use what you're comfortable with or can incrementally add to your muscle memory.

rzmmmMar 26, 2026, 9:59 AM
Oh wow I didn't know about this, thank you. The underlying feature is called "readline vi-mode" for folks who want to search more about it.
penguin_boozeMar 26, 2026, 11:32 AM
> <esc>cc

Doing control+o in insert mode temporarily places you into normal mode so that you can execute one normal-mode command, and then go back to insert mode again--no need to hit 'i' again.

So, instead of '<esc>cc', '<c-o>S'.

ahmedfromtunisMar 26, 2026, 1:18 PM
The vim version is much easier, if you ask me: 3 strokes, 2 keys and 0 combinations.

The one you suggest however requires 4 strokes (ctrl then o then shift then s), 4 keys (ctrl, o, shift, s) and 2 combinations.

The "cc" sequence deletes the line and switches automatically to insert mode. To forgo the switch, the sequence then becomes "dd".

ratrocketMar 26, 2026, 1:42 PM
Maybe I have my bash/readline vi mode configured specially to do this, but if I want to delete the entire line and type a new one (from anywhere in that line), I do something simpler than either of these alternatives:

<esc>S

Esc exits insert mode (of course) and capital S erases the line and puts you in insert mode at column 0 (just like in (n)vim, right?).

Like I said, maybe I configured that? But 'S' is standard vim-stuff... (I'm not able to double check my config at the moment).

[Edit: right after hitting submit I realized that my way is perhaps "arguably" simpler because I do have to hit shift to get capital S. So I'm also hitting three keys...]

maleldilMar 26, 2026, 1:46 PM
<c-o>S is also a vim sequence. The equivalent readline/emacs is <c-e><c-u> or <c-a><c-k>, or just <c-u> or <c-k> if you're already at the end/start of the line.
soraminazukiMar 26, 2026, 5:28 PM
Or just <C-u> in insert mode. <C-u> and <C-w> are standard Vim insert mode commands.

https://vimhelp.org/insert.txt.html#i_CTRL-U

commandlinefanMar 26, 2026, 7:39 PM
I've never understood why emacs mode became the default. "set -o vi" is the _first_ command I type in a new shell.
_doctor_loveMar 26, 2026, 9:18 PM
remap Caps Lock to Ctrl and see the light from home row
nidnoggMar 26, 2026, 1:34 PM
I've been a vim/nvim casual user for the past year or two, and I still feel as if I'm slightly less proficient in it for the amount of time that I put into it.

I really need to get around to playing with it more. I just hope that especially now with genAI that it's not too late for learning it further.

exceptioneMar 26, 2026, 10:32 AM

   <esc>3bcw
What is your keyboard layout? This looks like a crime against humanity on a regular qwerty kb.
ahmedfromtunisMar 26, 2026, 1:22 PM
I use qwerty and azerty, and in both I never felt typing the sequence was any harder than typing any other regular word. Generally speaking, I prefer sequential "shortcuts" then multikey bindings.
sva_Mar 26, 2026, 10:43 AM
Instead of esc, type ctrl [
exceptioneMar 26, 2026, 11:06 AM
Does it help a lot? You've still got a three to type which is a crime, plus some letters, only to move 3 words. My typing skills are not great, but that sounds like an awful lot of work(?)

If I hit CTRL + ARROW_LEFT 3 times, I am done a lot faster I guess. But I am open to learn, do people really use that and achieve the goal significantly faster?

gsinclairMar 26, 2026, 11:17 AM
I don’t love vi-mode, but I’ll address your comment.

Many people these days, including yours truly, have caps-lock mapped to ctrl if held or esc if tapped. That’s good ergonomics and worth considering for any tech-savvy person.

Instead of the 3b I would type bbb (because I agree with you that typing numerals is a pain).

So (caps lock)bbbcw isn’t bad. It’s better than it looks, because if you’re a vim user then it’s just so automatic. “cw” feels like one atomic thing, not two keypresses.

And importantly, it doesn’t involve any chords.

roxolotlMar 26, 2026, 1:08 PM
I think it’s a difference in how people think. I can’t remember hotkeys. It just doesn’t compute. But with vim style bindings it’s much closer to writing a sentence. `3`, number of times, `b`, beginning of word, `c`, change, `w`, word. Yea it’s a lot. I cannot explain why it’s simpler for me to learn that than emacs style bindings but it is.
helterskelterMar 26, 2026, 5:20 PM
Obligatory:

Your Problem with vim is you don't grok vi

https://stackoverflow.com/questions/1218390/what-is-your-mos...

sva_Mar 26, 2026, 3:41 PM
We're basically playing a game: if you have to leave homerow hand position, you've lost
lenkiteMar 26, 2026, 6:41 PM
Remap Capslock to Esc. Possible in every OS now.
ruptwelveMar 26, 2026, 1:00 PM
The <esc>v has been such a lifesaver at times when having to execute/modify super complex commands!
Ferret7446Mar 27, 2026, 2:27 AM
Eh, it's not that different from the default readline commands

A mistake 3 words earlier? No problem: <esc>3 Alt-b Alt-d

Want to delete the whole thing? Even easier: Ctrl-U

I can even use Ctrl-X Ctrl-e to open the command inside a fully-fledged EDITOR instance for more complex rework.

looshchMar 26, 2026, 9:10 PM
i went even further and use neovim as my multiplexer
fellertsMar 26, 2026, 8:44 AM
CTRL + W usually deletes everything until the previous whitespace, so it would delete the whole '/var/log/nginx/' string in OP's example. Alt + backspace usually deletes until it encounters a non-alphanumeric character.

Be careful working CTRL + W into muscle memory though, I've lost count of how many browser tabs I've closed by accident...

goplayoutsideMar 26, 2026, 8:06 PM
Firefox v147 finally added the ability to redefine keyboard shortcuts, including ^w: https://news.ycombinator.com/item?id=46952095

1. Load about:keyboard

2. Find "Close tab" and click "Clear" or "Change".

hejiraMar 26, 2026, 8:57 AM
In my terminal it's the exact opposite – Alt-Backspace deletes to the previous space, whereas Ctrl-W deletes to the last non-alphanumeric (such as /). I'm using fish shell in an Alacritty terminal.

Yeah, pressing Ctrl-W accidentially is a pain sometimes ... but Ctrl-Shift-T in Firefox is a godsend.

AerolfosMar 26, 2026, 9:26 AM
> Yeah, pressing Ctrl-W accidentially is a pain sometimes ... but Ctrl-Shift-T in Firefox is a godsend.

Fun fact: despite having absolutely no menu entry for it, and I believe not even a command available with Ctrl+Shift+P, Vscode supports Ctrl+Shift+T to re-open a closed tab. Discovered out of pure muscle memory.

dgrunwaldMar 26, 2026, 11:26 AM
It's a normal command called "View: Reopen Closed Editor".
AerolfosMar 27, 2026, 8:54 AM
You'd think that meant "window" since they consistently call the windows editors, but I guess not
fainpulMar 26, 2026, 10:01 AM
Set $WORDCHARS accordingly. In your case, remove / from $WORDCHARS.

https://unix.stackexchange.com/a/726014

exceptioneMar 26, 2026, 11:00 AM
For the bash people

  stty werase undef
  bind '"\C-w": backward-kill-word'

source: https://superuser.com/questions/212446/binding-backward-kill...
meatmanekMar 26, 2026, 9:12 PM
> Be careful working CTRL + W into muscle memory though, I've lost count of how many browser tabs I've closed by accident...

I still maintain this is why macOS is the best OS for terminal work -- all the common keybindings for GUI tools use a different modifier key, so e.g. ⌘C and ⌘W work the same in your terminal as they do in your browser.

(Lots of the readline/emacs-style editing keybindings work everywhere in macos as well -- ^A, ^E, ^K, ^Y, but not ^U for some reason)

p_alexanderMar 27, 2026, 8:00 PM
100% agree, and I am surprised I do not see this mentioned more often. I came up on Linux and then had to use MacOS for a job and got used to the cmd / ctrl separation and now I cannot use a terminal on Linux without major pain. I've tried a few of the key rebinding options and they all feel klunky.
gryfftMar 26, 2026, 8:51 AM
Ctrl-Shift-T usually brings that tab right back at least
figmertMar 26, 2026, 9:57 AM
> Be careful working CTRL + W into muscle memory though, I've lost count of how many browser tabs I've closed by accident...

This hurts.

Also, for the shell, if you do C+w, you can "paste" it back using C+y. Assuming you have not removed that configuration.

lelanthranMar 26, 2026, 7:20 PM
> Be careful working CTRL + W into muscle memory though, I've lost count of how many browser tabs I've closed by accident...

You're telling me!!!

(I use vim daily, with multiple splits in a single instance.)

naikrovekMar 26, 2026, 8:06 PM
CTRL+SHIFT+T will resurrect your most recently closed tab, with history. Pressing it again will bring up the next most recently closed tab, with history. Etc.

Or maybe you don’t use SHIFT. Can’t recall right now. My fingers know but I’m not at a computer.

Anyway, browser menus can also show you recently closed tabs and bring them back.

oxag3nMar 26, 2026, 5:36 PM
Depends on the shell - bash on my Ubuntu deletes entire '/var/log/nginx/', while after switching to sh it deletes only nginx
fp64Mar 26, 2026, 3:38 PM
I've installed "More Better Ctrl-W" for Chromium, and mapped Ctrl-W to do nothing, and Ctrl-D to close the current tab
arcanemachinerMar 26, 2026, 6:30 PM
But how am I supposed to create or edit a bookmark?
themafiaMar 26, 2026, 5:45 PM
'man readline' contains all the useful key combinations.
sfinkMar 26, 2026, 3:41 PM
...which is why I recently went to about:keyboard and removed that hotkey. I love that page.

That, and Ctrl-N. No more forest of blank browser windows when using a terminal emulator in a web page!

(Firefox only)

naikrovekMar 26, 2026, 8:09 PM
Ctrl+W is undoable.

Ctrl+Shift+T will undo your recent tab closures in reverse order. The tabs maintain their history as well.

I am very surprised at how many people in here don’t seem to know that. I learned about Ctrl+Shift+T before I learned about Ctrl+W. I was using the middle mouse button on a tab to close tabs before then.

sfinkMar 26, 2026, 8:14 PM
I know. I used to use it fairly often when Ctrl-W still did something. It helps, but (1) it doesn't work if you closed the last tab and thus the whole window, you'd need to restore recently closed windows instead; and (2) it is still more disruptive and potentially state-losing than preventing an unwanted close in the first place. Tab history retention isn't perfect.
tkocmathlaMar 26, 2026, 8:49 AM
I love this, from a comment on the article:

  He had in his path a script called `\#` that he used to comment out pipe elements like `mycmd1 | \# mycmd2 | mycmd3`. This was how the script was written:
 
  ```
  #!/bin/sh
  cat
  ```
rgrauMar 26, 2026, 10:08 AM
A similar trick:

    #!/bin/sh
    $*
that's my `~/bin/noglob` file, so when I call a zsh script from bash that uses `noglob`, it doesn't blow up.
000ooo000Mar 26, 2026, 10:21 AM
What does it provide over

mycmd1 #| mycmd2

chriswarboMar 26, 2026, 11:23 AM
Theirs "turns off" one element of a pipeline; yours turns off everything after a certain point.

This will output the stdout of mycmd1:

    mycmd1 #| mycmd2 | mycmd3
This will output the stdout of mycmd3:

    mycmd1 | \# mycmd2 | mycmd3
mkoryakMar 26, 2026, 12:19 PM
Can you explain to me why either of these is useful?

I've somehow gotten by never really needing to pipe any commands in the terminal, probably because I mostly do frontend dev and use the term for starting the server and running prodaccess

chriswarboMar 26, 2026, 1:03 PM
Pipelines are usually built up step by step: we run some vague, general thing (e.g. a `find` command); the output looks sort of right, but needs to be narrowed down or processed further, so we press Up to get the previous command back, and add a pipe to the end. We run that, then add something else; and so on.

Now let's say the output looks wrong; e.g. we get nothing out. Weird, the previous command looked right, and it doesn't seem to be a problem with the filter we just put on the end. Maybe the filter we added part-way-through was discarding too much, so that the things we actually wanted weren't reaching the later stages; we didn't notice, because everything was being drowned-out by irrelevant stuff that that our latest filter has just gotten rid of.

Tricks like this `\#` let us turn off that earlier filter, without affecting anything else, so we can see if it was causing the problem as we suspect.

As for more general "why use CLI?", that's been debated for decades already; if you care to look it up :-)

mkoryakMar 26, 2026, 9:49 PM
no no, not asking why use CLI. If I was less lazy, I would use it more often
agonsMar 26, 2026, 12:41 PM
I can imagine a pipeline where intermediate stages have been inserted to have some side effect, like debug logging all data passing through.
000ooo000Mar 26, 2026, 8:38 PM
Ah duh, cheers
internet_pointsMar 26, 2026, 9:53 AM
Yes! That one's going in my $PATH. Such a useful use of cat!
mzsMar 26, 2026, 5:06 PM
Wow I hate* that. I use bracket comments. They're cool cause they are bracket comments, so I use it in scripts to document pipelines. They are annoying cause they are bracket comments, in an interactive shell I have to type more and in TWO places. It's fun to reason-out how it works ;)

  $ echo foo | tr fo FO | sed 's/FOO/BAR/'
  BAR
  $ echo foo | ${IFS# tr fo FO | } sed 's/FOO/BAR/'
  foo
It's nice to have a way to both /* ... */ and // ... in shell scripts though:

  foo \
  | bar ${IFS Do the bar. Do it. } \
  | baz
* in the best possible way, like it's awful - I hate I didn't think of that
rgrauMar 26, 2026, 5:28 PM
for multiline pipes, it's WAY better to format like

    foo   |
      bar |
      baz 
You don't have to use backquotes, AND, it allows you to comment line by line, because there's no backslash messing with the parser.

I also use a last `|\ncat` so you can delete any line and you don't have to worry about the last line being a bit different than the rest

I created a list of similar tricks in https://github.com/kidd/scripting-field-guide in case anyone wants to take a look

mzsMar 26, 2026, 7:00 PM
You'll probably dislike this too:

  $ {
  >     echo foo \
  >     && echo bar \
  >     || echo baz ;
  > }
  foo
  bar
  <^P><^A>$<^F>IFS
  ${IFS#   echo foo   && echo bar   || echo baz ; }
  $ _
There's good and bad to both approaches. I like how I can use () and {} to bracket things and otherwise every line that end in \ is continued. I line-up on the left with the operator, you with indentation. When you use a # style comment, you have to look up and back and forward to see what the operator is you are continuing over to the next line:

  $ foo |
    bar | # ?Do? *the* $bar$ && [do] {it!}
    baz
Which only takes an extra neuron or so, but then history...

  <^P>
  $ foo |   bar | # ?Do? *the* $bar$ && [do] {it!}
  baz
rgrauMar 26, 2026, 7:36 PM
aha! I see what you mean, it's indeed a nice option, yep.

Using brackets like this is something I never thought of, and it's probably why it's hard for me to process it, but I can see it provides nice annotation capabilities, and it's a more self-contained style.

Thx for sharing!

hikarudoMar 26, 2026, 9:57 AM
One trick I use all the time:

You're typing a long command, then before running it you remember you have to do some stuff first. Instead of Ctrl-C to cancel it, you push it to history in a disabled form.

Prepend the line with # to comment it, run the commented line so it gets added to history, do whatever it is you remembered, then up arrow to retrieve the first command.

$ long_command

<Home, #>

$ #long_command

<Enter>

$ stuff_1 $ stuff_2

<Up arrow a few times>

$ #long_command

<home, del>

$ long_command

gvalkovMar 26, 2026, 12:36 PM
In zsh you can bind "push-line-or-edit". In bash and all readline programs, you can approximate it with C-u followed by C-y (i.e. cut and paste). My history is still full of '#' and ':' (csh trauma) prefixed command-lines like you described though ...
idoubtitMar 26, 2026, 7:02 PM
You missed an easier alternative that was in the article: ctrl-u saves and clears the current line, then you can input new commands, then use ctrl-y to yank the saved command.

With zsh, I prefer to use alt-q which does this automatically (store the current line, display a new prompt, then, after the new command is sent, restore the stored line). It can also stack the paused commands, e.g.:

$ cp foo/bar dest/ <alt-q>

$ wcurl -o foo/bar "$URL" <alt-q>

$ mkdir foo <enter> <enter> <enter>

philsnowMar 26, 2026, 7:59 PM
When you're killing (C-u, C-k, C-w, etc) + yanking (C-y), you can also use yank-pop (bound to M-y in bash and zsh by default) to replace the thing you just yanked with the thing you had killed before it.

  $ asdf<C-w>
  $                  # now kill ring is ["asdf"]
  $ qwerty<C-a><C-k>
  $                  # now kill ring is ["qwerty", "asdf"]
  $ <C-y>            # "yank", pastes the thing at the top of the kill ring
  $ qwerty<M-y>      # "yank-pop", replaces the thing just yanked with the next
                     # thing on the ring, and rotates the ring until the next yank
  $ asdf
fragmedeMar 26, 2026, 10:07 AM
Fwiw, in Bash, alt-shift-3 will prepend the current command with # and start a new command.
j4cobgarbyMar 26, 2026, 11:02 AM
More generally, it's alt-#. On an ISO (e.g. UK) keyboard layout, shift-3 isn't a hash.
dotancohenMar 27, 2026, 4:06 AM
Thank you so much! I do this constantly. For me it was Ctrl-A Shift-3 Enter - two keystrokes too many.
olejorgenbMar 26, 2026, 5:26 PM
Do yourself a favor and upgrade your history search with fzf shell integration (or similar): https://youtu.be/u-qLj4YBry0?t=223 / https://junegunn.github.io/fzf/shell-integration/
gawsMar 27, 2026, 6:29 PM
Or use atuin[1]

[1]: https://atuin.sh/

zahlmanMar 26, 2026, 8:17 AM
Not a fan of the LLM-flavoured headings, and the tips seem like a real mixed bag (and it'd be nice to give credit specifically to the readline library where appropriate as opposed to the shell), but there are definitely a few things in here I'll have to play around with.

One thing I dislike about brace expansions is that they don't play nicely with tab completion. I'd rather have easy ways to e.g. duplicate the last token (including escaped/quoted spaces), and delete a filename suffix. And, while I'm on that topic, expand variables and `~` immediately (instead of after pressing enter).

croemerMar 26, 2026, 6:28 PM
Not just the heading is LLM-flavoured. So is the writing, e.g. "The shell is a toolbox, not an obstacle course."
zahlmanMar 26, 2026, 7:12 PM
Yeah, there are a few of those, but overall there wasn't really enough prose in total to really irritate me. And those LLM-isms do come from somewhere, and I really do get the sense that some humans are effectively training themselves off of AI now.
ta8903Mar 26, 2026, 9:25 AM
Speaking of readline, I recently found out PowerShell has a readline mode (https://learn.microsoft.com/en-us/powershell/module/psreadli...) and it works great.

As someone who works mostly in WSL and has to use PS occasionally, it really reduces the overhead of the context switch.

umanwizardMar 26, 2026, 2:55 PM
Readline is close enough to being part of bash that it’s not really inaccurate to call these all shell features imo.
integralidMar 26, 2026, 4:47 PM
Except not everyone uses bash shell - so it's not really accurate.
elricMar 26, 2026, 12:07 PM
Regarding history: I have a function in my ZSH config which excludes certain things from the history. Especially things that can break stuff when my sausage fingers CTRL-R the wrong thing

Something like this:

    # Prevent certain strings from appearing in the history
    # Anything starting with a leading space is ignored
    # Anything containing "--force" or "whatever" is ignored
    function zshaddhistory() {
      emulate -L zsh
      if ! [[ "$1" =~ "(^ |--force|whatever)" ]] ; then
          print -sr -- "${1%%$'\n'}"
          fc -p
      else
          return 1
      fi
    }
rgrauMar 26, 2026, 5:33 PM
That's very cool!

To take advantage of the "leading space" one, I have this, to mark some commands that I never want to record:

       unhist () {
         alias $1=" $1"
       }
       unhist unhist
       unhist fzf
       unhist rghist     #custom command that greps .zhistory,...
voidUpdateMar 26, 2026, 8:49 AM
With ctrl+r, if you press it twice, it will autofill the search with whatever you last searched for. pressing it more will go back through the history. Been using that a lot recently when doing docker stuff. ctrl+r, type the container name, keep going until I get the compose build command. ctrl+r, ctrl+r, repeat until the log command. Then I can just mash ctrl+r to get the build and log commands. Ctrl+r is your friend. ctrl+r
arcanemachinerMar 26, 2026, 9:21 AM
Make sure to add fzf + shell integration for maximum Ctrl+r goodness.
ZeroGravitasMar 26, 2026, 1:07 PM
Also worth reading the intro to fzf search syntax.

https://junegunn.github.io/fzf/search-syntax.

The $ and bang and exact search are neat, but the bit at the bottom as to why `gadd` or `gas` is a better search for `git add something` than something with full words and spaces is a revelation when first using fzf.

talkinMar 26, 2026, 9:02 AM
> cd -: The classic channel-flipper. Perfect for toggling back and forth.

And not only cd. Gotta love 'git checkout -'

piekvorstMar 26, 2026, 10:49 AM
The '-' shortcut is weird. In 'git commit -F -', the '-' is actually /dev/stdin.
mpyneMar 26, 2026, 1:35 PM
`-` is the traditional shell way to refer to stdin/stdout (as with your git commit example) but also the traditional way to refer to the last directory you were in (as with git checkout/switch).

You would never pipe the output of a command to `cd` so the `-` shortcut couldn't be helpful to cd as-is. So rather than invent yet another shortcut to memorize for `cd` they reused the existing one which otherwise would be redundant, which I appreciate at least.

But git is simply being consistent with the shell to further reduce the cognitive complexity of reusing shell commands you're used to in analogous git contexts.

account42Mar 26, 2026, 1:24 PM
- is a pretty standard idiom for using stdin/stdout instead of a named file that you can find in many commands. I don't think it conflicts with the cd/checkout usage though as there the argument normally does not refer to a file so having - mean stdin/stdout doesn't make sense.
nasretdinovMar 26, 2026, 10:10 AM
I'd advise against using sudo !! though since it adds the command to history and then it's very easy to accidentally trigger, running some undesired command as root without any prior confirmation. IMO pressing up, Ctrl-A and typing "sudo " isn't much longer but saves you from running unknown commands as root by accident
teo_zeroMar 27, 2026, 7:40 AM
Pressing up, Ctrl-A and typing "sudo " adds the command to history, too. What's the difference?
em-beeMar 26, 2026, 1:51 PM
i never found !! useful at all when i can just use up arrow to get the entry i want. it becomes more interesting when you can recall older commands, but then too i prefer search because i want to verify what command i am going to run.

and i only use sudo to open a root shell. never to run anything directly. i don't want normal and root commands mixed in the same history.

i could keep sudo commands out of the history, but then i don't have any history for stuff done as root.

with tmux i can switch terminals easily, so i am also not tempted to run things as root that i shouldn't despite having a root shell open.

bandie91Mar 26, 2026, 2:33 PM
> i want to verify what command i am going to run.

shopt -s histverify

shopt -s histreedit

i dont know why they are not the default.

kgwxdMar 26, 2026, 10:32 AM
Decades ago, i used a small dns host. I wanted to switch a personal site and they just couldn't get the final step of the transfer to work. A ton of "try now" emails spanning several weeks.

Then one day, I was trying to setup MySQL on a personal Linux machine, and it wouldn't let me use my "standard password" for the admin account. I knew I could just use a different one, but I really wanted to know what the problem was. Took a long time, and I don't remember how I figured it out, but I eventually tracked it to the password ending with '!!'.

It took a while to put it together, and I never confirmed with the dns host support it's what fixed the issue but, I changed my password there, tried the transfer again, and it worked without any help from support. I suspect my plaintext password played some part in a script used in the transfer process, and was outputting the previous command in place of the !! I wish I had asked them if that was it, but if it was, they would have to admit to having my plain text password, or lie about it.

000ooo000Mar 26, 2026, 10:28 AM
I have a bash key binding, Ctrl+Y, that prepends sudo to the current command and submits it. I also don't use sudo-rs. No one has died yet.
cocotoMar 26, 2026, 12:31 PM
Prepend your command with a space and now your command is not saved in the history.
sltkrMar 26, 2026, 12:50 PM
That depends on the shell configuration.

On bash, you can achieve this by setting HISTCONTROL=ignorespace but that's not the default.

kwar13Mar 26, 2026, 11:42 PM
in zsh pressing esc twice appends sudo to the last command
kleibaMar 26, 2026, 4:10 PM
Just recently, I came up with this in my .bashrc, basically a "deep cd" command:

    dcd() {
        # If no argument is given, do nothing
        [ -z "$1" ] && return

        # Find the first matching directory under the current directory
        local dir
        dir=$(find . -type d -path "*$1*" -print -quit 2>/dev/null)

        # If a directory was found, cd into it
        [ -n "$dir" ] && cd "$dir"
    }
I thought this would be way too slow for actual use, but I've come to love it.
cipritomMar 26, 2026, 4:27 PM
you should look into autojump which has `jc` (jump child), or other similar flavours of "smart cd" (z, fzf, etc)
kleibaMar 26, 2026, 5:47 PM
Thanks, but I like that this is just a small, simple bash function without the need to install 3rd-party software.
WalfMar 26, 2026, 2:16 PM
The utility of $_ is often voided by tab-completion in the subsequent command, at least in bash. You won't know what it contains, which makes it dangerous, unless you first check it in a way that also carries it forwards:

printf %s\\n "$_"

piekvorstMar 27, 2026, 7:21 AM
Even without tab completion, the variable can hold unexpected values due to user error (you don't see the command as a whole), multiple shell windows, or forgotten context.

Relying on it even in limited scenarios can train an invisible habit that would backfire at the least expected moment.

Any assistance intended for immediate action should itself be immediate, not indirect.

ameliusMar 26, 2026, 9:43 AM
What confuses me is that Ctrl+Y "yank" means the opposite of what it means in Vim. Certainly does not help with keeping my sanity.
antiframeMar 26, 2026, 3:53 PM
It all depends on your perspective.

Are you yanking into your kill ring or yanking out of your kill ring? I had trouble with yanking and killing until I realized the complement to yanking, killing, only makes sense in the into-the-kill-ring" direction, so yanking must be out of the kill ring.

When I use vim, which I don't think has a kill ring but registers, I think I am yanking into a register and then pasting from a register later.

So, just ask yourself this: "are you using a kill ring or register to store your text?" and the answer becomes clear.

alex_smartMar 26, 2026, 5:21 PM
That is because the terminology (and the keybindings) come from the Emacs tradition, not vim. Most shells come with “vim mode” as well, but at least in my experience, the dual mode editing paradigm of does not feel like a good fit for the shell.
prodigycorpMar 26, 2026, 10:25 AM
There's one thing you need to only think about once, and has the potential to save you a ton of time: profile your ZSH startup time!

Stuff like NVM or Oh My ZSH will add a few seconds to your shell startup time.

sva_Mar 26, 2026, 10:51 AM
I can recommend powerlevel10k with instant prompt enabled.

https://github.com/romkatv/powerlevel10k

wewtyflakesMar 26, 2026, 5:39 PM
Agreed. I lazy-load NVM to get around that:

  lazy_nvm() {
    unset -f nvm node npm npx
    [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
  }
  nvm()  { lazy_nvm; nvm "$@"; }
  node() { lazy_nvm; node "$@"; }
  npm()  { lazy_nvm; npm "$@"; }
  npx()  { lazy_nvm; npx "$@"; }
chrisweeklyMar 26, 2026, 1:43 PM
good call

if you care about perf, fnm is better/faster/cleaner than nvm. (also, mise is able to manage "all the things", not just node)

IME omzsh slowness usu relates to overloading it w plugins, which I've never found a need for...

gchamonliveMar 26, 2026, 4:38 PM
For me the ultimate trick is to open the current prompt in vim with F2 (Ctrl+X ctrl+E seems to work too):

  # Use F2 to edit the current command line:
  autoload -U edit-command-line
  zle -N edit-command-line
  bindkey '^[OQ' edit-command-line  # f2 is ^[OQ; to double check, run `xargs` and then press f2
tzotMar 26, 2026, 7:52 PM
> # f2 is ^[OQ; to double check, run `xargs` and then press f2

I remember using `cat -v` before learning that `xargs` exists… or maybe before `xargs` actually existed on systems I used :)

nickjjMar 26, 2026, 10:43 PM
CTRL+L isn't the same as clear btw, it really maps back to `clear -x`.

CTRL+L clears the visible output but you can still scroll up in your buffer to see the rest, clear will clear that scroll up buffer too.

I've written about and demo'd this in https://nickjanetakis.com/blog/clear-vs-ctrl-l-in-your-shell.

0xcb0Mar 26, 2026, 12:09 PM
I've been using a lot of key combinations and I wasn't aware of these two, and I really think these are awesome additions to handling the console. Thank you for showing me. I've only been using it for 22 years, but I haven't come across these :D

`CTRL + U and CTRL + K CTRL + W`

What I like about these key combinations is that they are kind of universal. A lot of programs on Linux and Mac support all these key combinations out of the box. And that's like a game changer in productivity, especially jumping to the start or the end of the line or jumping forward and backward per word is making working only with the keyboard so much more nice. And in editors together so AVY, you can even get a faster flow of jumping around.

antiframeMar 26, 2026, 3:47 PM
Yes, those are shortcuts used in the GNU readline library, which many programs use whenever they need to read lines of text interactively from their operators. Notable examples are (most) shells, (most) interpreters, and tools like ftp, fzf, etc.

Notably, these keybindings are it's default map, which comes from the GNU's project editor Emacs. But, there is also the POSIX-compliant, but not-default, editing mode based on Bill Joy's visual editor (vi).

martinflackMar 26, 2026, 4:10 PM
I use `!!` quite a bit to repeat the output of the prior command as an argument.

    # it's in my PATH but can't remember where
    which myscript
    vi `!!`
tzotMar 26, 2026, 8:08 PM
On scripts that might handle filenames with spaces, I include:

    IFS='   ''
    '
Hint: the spaces between the first two apostrophes are actually one <Tab>.

This does not affect the already written script (you don't need to press Tab instead of space to separate commands and arguments in the script itself), but by making <Tab> and <LF> be the “internal field separators” will allow globbing with less quoting worries while still allowing for `files=$(ls)` constructs.

Example:

    IFS='   ''
    '
    echo hello >/tmp/"some_unique_prefix in tmp"
    cat /tmp/some_unique_prefix*
    fn="My CV.txt"
    echo "I'm alive" >/tmp/$fn
    cat /tmp/$fn
Of course this will still fail if there happens to be a filename with <Tab> in it.
piekvorstMar 27, 2026, 8:42 AM
I can't reproduce the glob expansion problem.

    % echo test >'/tmp/hello world'
    % cat /tmp/hello*
    test
This is bash 5.3.9.

Still, I couldn't agree more on limiting IFS. Personally, I set it only to <LF>.

In my scripts, I rely on the $(ls) idiom heavily. People I've talked to consider this an anti-pattern and suggest relying on -0, -z, --zero, --null, and -print0 flags instead. I don't deny that it's better than nothing when correctness is the goal, but I’d counter that shell is more about using a familiar interface (text representation) to solve new tasks, not about writing correct code (that’s the domain of other languages). An uncritical pursuit of correctness often results in convoluted code.

(I know that $(ls) is a subject to various expansions. I solve this problem by using a shell that doesn't do that [1].)

Another consideration is that /bin/ls and /bin/find are not the only sources of filenames. Sometimes the source is third-party or has to be user-friendly (and thus separated by traditional newlines).

Some typographical issues just can't be solved by a pursuit of mechanistic correctness. For another example, the \.txt$ idiom wouldn't work if spaces are allowed at the end of filenames. Those problems are not even shell-specific.

Those are just a few of my personal notes. Fortunately, there's a more systematic and comprehensive study of this issue [2].

[1]: https://9p.io/sys/doc/rc.html

[2]: https://dwheeler.com/essays/fixing-unix-linux-filenames.html

alkhMar 26, 2026, 10:05 PM
This snippet for zsh still has some rough edges but works for the majority of cases. Automatically extends any global alias when space is pressed in zsh. For ex. I have `alias -G G='rg -s'`, so if I type `command | G` it will autoexpand it to `command | rg -s` and so on.

  globalias() {
    local raw word
    # raw last blank-separated token, exactly as typed
    raw=${LBUFFER##\* }
    # shell-parsed last word
    word=${${(z)LBUFFER}[-1]}
    # if user typed \alias, don't expand
    if [[ $raw == \\* ]]; then
        zle self-insert
        return
    fi
    if alias -- ${(q)word} &>/dev/null; then
        zle _expand_alias
        zle expand-word
    fi
    zle self-insert
}

zle -N globalias bindkey ' ' globalias

MattGrommesMar 26, 2026, 6:46 PM
If only somebody had a lifehack for making me remember all these awesome commands.

If I do something the slow way it's usually because I don't do the operation enough to burn it into my memory, or I got burned by accidentally hitting something close but incorrect once and closed the tab or something.

stevthegouwsMar 26, 2026, 10:17 PM
I find spaced repetition Anki flash cards surpisingly effective for this kind of thing.

You’d think remembering tonnes of shortcuts and commands and flags would be alot of effort but it’s surprisingly low effort when using cloze deletions and phrased like:

- “… is to delete the last word” - “Ctrl w is to …”

If you’re not familiar with spaced repetition it’s worth checking out, especially if you have a holey memory like mine.

https://ncase.me/remember/

w-llMar 26, 2026, 6:48 PM
post-it note until you dont need it anymore
shigawireMar 26, 2026, 6:54 PM
I hate to be the AI guy, but a coach that lived in my terminal and corrected me when I do it the slow way would actually help.
smcameronMar 27, 2026, 11:32 AM
On the "reset"/"stty sane" trick, I also sometimes have found it necessary to press Ctrl-J rather than RETURN at the end of the command.
ruptwelveMar 26, 2026, 1:02 PM
Maybe not a shell trick per-se but I have been a very big fan of zoxide. It can jump around your common directories. If you have a ~/workspace/projects and you are anywhere and type `cd projects` it will take you to that directory. I never realized how much I got hooked onto it, until I used a system without it.
llarssonMar 26, 2026, 6:21 PM
Built in functionality that may offer something similar:

https://linuxhandbook.com/cdpath/

fzeindlMar 26, 2026, 11:32 AM
My header on top of every script

            #!/usr/bin/env bash
            set -eEuo pipefail
            # shellcheck disable=SC2034
            DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
            #######################################################
a-french-anonMar 26, 2026, 4:12 PM
I'd suggest `pwd -P` to resolve symlinks too. (if you use DIR to call/source neighbouring scripts).
TacticalCoderMar 26, 2026, 3:14 PM
Wait... Most of my shell scripts have zero unused variables: I prefer to comment them if I may need them later on.

Why do you disable SC2034?

I don't think not having unused variables prevent me from doing things in my scripts!?

I understand if it's a preference but SC2034 is basically one of my biggest timesavers: in my case unused variables are typically a bug. Except, maybe, ANSI coloring variables at the top of the script.

fzeindlMar 26, 2026, 5:28 PM
I disable it only for the DIR variable which I might not use.
void-starMar 26, 2026, 1:41 PM
set -o vi

<esc> puts you into vi mode at the cli prompt with all the semantics of the editor.

These carpal tunnel riddled hands can’t be bothered to reach for ctrl or alt let alone arrow keys.

cess11Mar 26, 2026, 3:46 PM
If you aren't aware already, you can put 'setxkbmap -option ctrl:swapcaps' in one of your startup config files, like .bashrc or somesuch. That flips left CTRL and CAPS LOCK.
coopykinsMar 26, 2026, 1:45 PM
My favourite QoL improvement to any shell I use is to improve the history function(Ctlr+R)I personally like https://github.com/cantino/mcfly
chasilMar 26, 2026, 8:36 AM
A much larger base for ksh (as a pdksh descendent) is Android. OpenBSD is a tiny community in comparison, although Android has acquired code directly from OpenBSD, notably the C library.

The vi editing mode is always present in ksh, but is optional in dash. If present, the POSIX standard requires that "set -o vi" enable this mode, although other methods to enable it are not prohibited (such as inputrc for bash/readline), and as such is a "universal trick."

The article is relying on some Emacs mode, which is not POSIX.

$_ is not POSIX if I remember correctly.

History in vi mode is easier, just escape, then forward slash (or question mark) and the search term (regex?), then either "n" or "N" to search the direction or its reverse.

I've seen a lot of people who don't like vi mode, but its presence is the most deeply standardized.

commandersakiMar 26, 2026, 10:11 AM
My favourite trick is either commenting out a whole command or placing a comment at the end of a command to make it easier to find in my persistent history (thanks eliben) [0], using the # character.

I tried this in zsh and it wasn't the default behaviour which immediately made me nope from the shell altogether, among all the other quirks. I've just been using bash for far too long to switch to something different.

[0] https://eli.thegreenplace.net/2013/06/11/keeping-persistent-...

exceptioneMar 26, 2026, 10:35 AM
I didn't know the `ALT + .` trick to repeat the last argument, but what is even more neat (and not mentioned in the article) is that it cycles through your history. At least it does in my shell.
fp64Mar 26, 2026, 3:43 PM
Here's my favorite tip: If you use bash, you can write bash on your prompt (duh). But this is one of the biggest reasons I stick with bash everywhere, as I am quite comfortable and experienced in bash and sometimes it's just easier to write things like `for i in *.mp3; do ffmpeg -i $i ...` etc. If it's re-usable, I write it to a bash script later.
integralidMar 26, 2026, 5:24 PM
That's vaccously true as you said isn't it? I write fish on my shell and then I can save it as a fish script. Worth noting that bash is much more portable and available by default, but if I'm going for portability I go straight to /bin/sh
fp64Mar 26, 2026, 6:30 PM
Fair point, but for scripting I don't feel fish (or zsh) offer an advantage big enough to bother learning that language with their rather narrow scope. But bash it's good to anyways know, you don't really get around it either. Larger/more complex scripts I write in other languages (depending on domain I and other requirements I guess). It's also not that I daily write those scripts on my shell, so I also think that even if I learned fish or zsh, I would have to look up things again every time I need to write something again.
thibranMar 26, 2026, 6:41 PM
Its almost ironical that we still use the Terminal - and many use it like in the eighties using Bash - and seem to have forgotten that we should invent a better terminal & shell than doing all the workarounds to handle the quirks of the current systems.
mmh0000Mar 26, 2026, 6:59 PM
Make a better system, and we'll consider using it.

A Terminal + Bash/ZSH is soooo sticky because they are VERY good at what they do once you learn the basics and quirks. And now with LLMs, CLIs are even better because LLMs talk in text and CLIs talk in text.

Microsoft tried with PowerShell to design a better system; it "technically" is better, but not "better enough" to justify the cost of switching (on Linux). The same is true of nushell; it is "better", but not better enough to justify switching for most people.

I believe we're at "peak input method" until someone invents Brain<->Computer interfaces.

thibranMar 26, 2026, 7:25 PM
I use the Terminal all the time and write my own CLI tools, but I'm feeling more and more the limits of the current system. With the years I have used almost all available shells (EShell was even my default for some time). Right now my favorite shell is Nushell, but still, it feels dated compare to what is possible on modern computers.

> Make a better system, and we'll consider using it. It's on my TODO list, but it will break with all conventions and tools (no TTY). My idea is to bring the chain-things-together idea to the 21st century using a keyboard first GUI.

bigstrat2003Mar 27, 2026, 12:16 AM
Powershell and nushell are both miles better than bash and its descendants. I switched to nushell and you couldn't pay me to go back to bash. I only wish that it was kosher to install it on servers at work, but alas it isn't so I have to suffer with bash when managing systems.
bigstrat2003Mar 27, 2026, 12:18 AM
We did! Nushell and Powershell are both so much better than bash that it's not even funny. There's zero reason to use a bash derivative in this day and age, they only persist through inertia + a minority of masochists actually like bash.
stormedMar 26, 2026, 7:18 PM
You'll look like the coolest person in the office running `sudo !!`. Another personal favorite of mine is using the --now flag for systemctl to enable & start a service in one command (i.e `systemctl enable --now nginx`)
Joker_vDMar 26, 2026, 8:45 AM
> The “Works (Almost) Everywhere” Club

> The Backspace Replacements

Also known as "emacs editing mode". Funnily enough, what POSIX mandates is the support for "vi editing mode" which, to my knowledge, almost nobody ever uses. But it's there in most shells, and you can enable it with "set -o vi" in e.g. bash.

ZeroGravitasMar 26, 2026, 9:07 AM
Vi mode is also available in Claude code and gemini-cli to give some recent examples, and a bunch of other places you might not expect it, as well the more obvious places where code is written.

Once you get used to it, it is painful to go back.

mr_mitmMar 26, 2026, 9:27 AM
My biggest complaint about the fish shell is the lack of true vi mode. They attempt to emulate it and it works to some degree, but it's no comparison to readline's implementation.
maleldilMar 26, 2026, 2:01 PM
You can always use Alt-E to open the command line in $EDITOR if you need more powerful commands. I find it better to use readline for small changes and jumping to vim for bigger ones.
dunbMar 26, 2026, 3:34 PM
What is it lacking in your eyes that makes it not true? I find fish’s vi mode more ergonomically complete for things like editing multi-line commands
mr_mitmMar 26, 2026, 3:51 PM
Just pressing `xp` to swap two characters does not work in fish. Combining deletion with a movement also does not work (e.g. `d3w` to delete three words).
krobelusMar 27, 2026, 2:29 PM
these have been fixed as of 4.4.0
mr_mitmMar 27, 2026, 3:21 PM
Awesome! That released hasn't landed yet in my distro's repos. Thanks a lot! Fish is a great product.
umanwizardMar 26, 2026, 3:04 PM
Have you tried a recent version? An issue I opened about this years ago was finally closed, they claim it’s fixed now. I haven’t tried the purported fix, though.
mr_mitmMar 26, 2026, 3:51 PM
Yes. It has improved, but it's still not there, and probably never will be. See my reply to your sibling comment.
worksonmineMar 26, 2026, 10:24 AM
And if you set `set editing-mode vi` in ~/.inputrc (readline configuration) you'll have it in even more places.
ta8903Mar 26, 2026, 9:29 AM
Something that should be mentioned is starting a command with a space doesn't add it to your history in most shells, really useful for one-off commands that you don't want cluttering your history.

Also, increase your `$HISTSIZE` to more than you think you would need, there have been cases where it helped me find some obscure command I ran like 3 years before.

l72Mar 27, 2026, 11:12 AM
Also a good thing to remember if you are ever dealing with credentials:

  $  APIKEY=asdfdfds
  $ curl -H "x-api-key: $APIKEY" https://example.com
account42Mar 26, 2026, 1:28 PM
HISTCONTROL=erasedups can also help keeping more obscure commands in your history, at the expense of context around commands.
SoftTalkerMar 26, 2026, 4:15 PM
I knew most of these but the $_ variable and "ESC + ." to reference or insert the last argument of the previous command. I can see getting some use out of that, so thanks for posting.
t312227Mar 26, 2026, 4:37 PM
or - as an alternative to <esc> + ".":

for the last argument

* <alt> + "."

if you want the -<n>th argument:

* <alt> + "_" # n times :=)

* <alt> + "."

cheers a..z

arttaboiMar 26, 2026, 4:24 PM
"cd -" is a lifesaver. Thank you so much for this.
egorfineMar 26, 2026, 12:02 PM
I'm using bash for over 30 years and I still find new things. Nice.
vdmMar 26, 2026, 9:31 AM
Ctrl-r works well at searching character trigrams, which can include space. Trigrams without space work well with auto_resume=substring .

`| sudo tee file` when current user does not have permission to >file

tehMar 26, 2026, 11:38 AM
Another useful "Emergency exit" is CTRL+Z which stops the process and cannot be intercepted.

It's often faster than hitting CTRL+C and waiting for process cleanup, especially when many resources are used. Then you can do e.g. `kill -9 $(jobs -p)` to kill the stopped tasks.

dasyatidprimeMar 26, 2026, 2:06 PM
All of the keyboard-driven terminal signals can be intercepted; catching INT (^C) for cleanup is just more common than the others. Only KILL and STOP cannot be caught.

^Z sends TSTP (not STOP, though they have the same default behavior) to suspend; some programs catch this to do terminal state cleanup before re-raising it to accept the suspension. Catching it to do full backout doesn't make as much sense because the program anticipates being resumed.

^\ sends QUIT, which normally causes a core dump and is rarely caught. If you have core dumps disabled (via ulimit -c 0 or other system configuration) then you can often use it as a harder version of ^C; this is how I would tend to get out of ‘sl’ in places where I found it unwantedly installed.

drzaiusx11Mar 26, 2026, 11:40 AM
ctrl-z pauses the process, it doesn't terminate. I think of z as in zombie as you can then run fg to bring it back from paused state or as you suggested kill in it for good
tzotMar 26, 2026, 8:17 PM
For the most simple case of a single job, I use the job number (`[1]` in the example) with %-notation for the background jobs in kill (which is typically a shell builtin):

    $ cat
    ^Z[1] + Stopped                    cat
    $ kill %1
williamcottonMar 26, 2026, 12:10 PM
Undo:

  Ctrl + _ (Ctrl + underscore)
bandie91Mar 26, 2026, 2:38 PM
it did not work for me in putty, so i added ctrl-x + ctrl-u too:

  bind '"\C-x\C-u": undo'
  bind '"\C-_": undo'
kwar13Mar 26, 2026, 11:40 PM
that was fantastic, learned a couple things after all these years too. alt+. ftw
tetris11Mar 26, 2026, 8:22 AM
Never heard of instant truncate, nor `fc`, nor `Esc .`

Quite a few useful ones

annie511266728Mar 27, 2026, 6:23 AM
The annoying part is not learning these, it’s remembering them at the right time.

I’ve started keeping a tiny cheatsheet just to avoid rediscovering the same tricks over and over.

TheServitorMar 26, 2026, 1:06 PM
great list but really overboard on the AI generated persona
piekvorstMar 26, 2026, 11:07 AM
Is it just me, or is it an LLM language? The article tries very hard to be correct but somehow lacks experience.

I've never used the majority of these tricks for decades, except for brace expansion, process substitutions, and complex redirections.

xeyowntMar 26, 2026, 11:47 AM
I knew many of these tricks, but learned many new tricks I didn't know and looks very useful (like you can do Ctrl-Y after an Ctrl-U, the 'reset' or 'disown' thing).

Regarding experience, I'm also struck by how many "experienced" engineers are just clueless with the keyboard.

codeinredMar 26, 2026, 5:19 PM
I think the keybinding suggestions are really nice. My shell is configured by default such that Alt+Left and Alt+Right move by a word, but having things that work out of the box, basically always, is really useful whenever I need to do things inside a docker container
rdevillaMar 26, 2026, 6:23 PM
set -o vi
scuff3dMar 26, 2026, 5:27 PM
Great write up, had to bookmark so I can go through it more later there so much good stuff in there.

For the CTRL + R tip, you can make it even better if you install fzf. Massively improves searching through history. It's worth the install just for that one feature.

Best thing I ever did as a dev was start spending more time in the terminal. Getting familiar with the tools and how they interact makes life so much easier.

chinadataMar 26, 2026, 5:18 PM
only the people do not use pageup and pagedown is who really know how to use shell
aa-jvMar 26, 2026, 8:20 AM
My favourite shell trick is to comment my code:

  $ some_long_command -with -args -easily -forgotten # thatspecialthing
... Some weeks later ..

  $ CTRL-R<specialthing>
.. finds:

  $ some_long_command -with -args -easily -forgotten # thatspecialthing

Need to see all the special things you've done this week/whenever?

  $ history | grep "\#"
...

Makes for a definite return of sanity ..

scbrgMar 26, 2026, 3:37 PM
I once saw this pattern referred to as a bashtag, which I think was an excellent name (no matter if you actually run bash as your shell or not).
skydhashMar 26, 2026, 12:48 PM
I don’t keep history. Any commands I think will be useful, I save it in a script.
senectus1Mar 26, 2026, 8:34 AM
omg >$ CTRL-R<specialthing>

I could kiss you.. this alone is amazing!

000ooo000Mar 26, 2026, 10:23 AM
!?specialthing?

If you are feeling brave

fragmedeMar 26, 2026, 8:59 AM
http://atuin.sh adds a database to store history in and a custom app to use for lookup with added modes to help with searching.
aa-jvMar 26, 2026, 8:41 AM
Yes indeed, it is very fun to discover this if you don't know it already, it expands your understanding of your shell life immensely, doesn't it?
keyboredMar 26, 2026, 10:52 AM
> We’ve all been there.

Close tab.

I ought to migrate away from shell scripting and just keep the shell for interactive use. Unfortunately I have cursed myself by getting competent-ish with P. shell and Bash scripting. Meaning I end up creating maintenance headaches for my future self.

(Echoes of future self: ... so I asked an LLM to migrate my shell scripts to Rust and)

Anyway with the interactive shell stuff. Yeah the I guess Readline features are great. And beyond that I can use the shortcut to open the current line in an editor and get that last mile of interactivity when I want it. I don’t really think I need more than that?

I tried Vim mode in Bash but there didn’t seem to be a mode indicator anywhere. So dropped that.

Edit: I just tested in my Starship.rs terminal: `set -o vi`. Then I got mode indicators. Just with a little lag.

joombagaMar 26, 2026, 1:07 PM
You can use `set vi-ins-mode-string` and `set vi-cmd-mode-string` in .inputrc to get indicators in readline, and you can add them to your prompt with a bit more work: https://superuser.com/questions/1466222/move-vi-mode-string-...
quijoteunivMar 26, 2026, 10:05 AM
Guilty as charged
ameliusMar 26, 2026, 10:13 AM
What I hate is that if you start a command with a space it is not recorded in the history. This happens often when copy+pasting commands. I know you can turn it off but still ... this drives me mad.
frou_dhMar 26, 2026, 12:08 PM
AFAIK that setting is opt-in, at least in Bash.
joombagaMar 26, 2026, 1:12 PM
Yeah but some operating systems have HISTIGNORE in (or sourced from) their skeleton files.
faangguyindiaMar 26, 2026, 9:07 AM
I just open, agent in tui, and ask it to do what I want and make a plan, i read the plan edit it and run it.

Simple, no need to learn any commandline these days.

I used to use arch and all, and managed many big projects. I find little value in learning new tools anymore, just feed it docs and it generated working plan most of the time

Now I've moved to coding in Haskell, which i find suits me better than wasting my time with cli and exploring what options all these cli tools have.

chriswarboMar 26, 2026, 11:33 AM
I'm confused; how is writing a shell command (using shortcuts like those in the article!) "wasting time", but describing what you want to an LLM, having it make a plan, reading the plan, editing it, and running it is somehow not a waste of time?

You also mention there being "little value", when your proposed approach costs literal money in form of API/token usage (when using hosted models).

> Now I've moved to coding in Haskell

You might like https://hackage.haskell.org/package/turtle or http://nellardo.com/lang/haskell/hash/

worksonmineMar 26, 2026, 10:14 AM
What is it like to be this proud of not learning the tools you use? Do you really think several paragraphs to an agent that may or may not be correct is the "easy" way compared to just checking the manual for the flag you want?

I will never understand people like you.

faangguyindiaMar 26, 2026, 11:16 AM
Tools are means to end.

They don't matter much to me.

bigstrat2003Mar 27, 2026, 12:22 AM
That's fine to a point. But if you don't learn your tools, you will have rendered yourself unable to catch when the LLM gets things wrong (and it will get things wrong because it doesn't understand anything it touches). That, in turn, will mean that you're going to struggle to reach your desired ends but won't have the understanding to figure out what's wrong.

"Tools are just a means to an end" means you need to not get attached to a tool if it's not doing the job. It doesn't mean you don't need to understand your tools.