Hacker News new | past | comments | ask | show | jobs | submit login
$!134 can be a nice bash foot shooter if you accidentally mistype the number
27 points by isenhaard on Dec 28, 2021 | hide | past | favorite | 51 comments
I'm coding for a few years now, but today it was the first time I mistyped

$!<number>

to repeat a command from the bash history. Fortunately it only launched a Python server. But finally you could accidentally hit any command from your past. It's like playing the lottery :-P




Fortunately my memory was never good enough for me to use that facility. C-r is how I always lookup earlier commands.


I do this too, but you know what is an even cooler and more rewarding way to exploit the shell history?

By COMMENTING your commands:

$ grep -i myname /etc/passwd # passgrep

.. ..

$ Ctrl-R "passgr"

It is so rewarding to do some intense bash work with liberal command line comments and then come back a few weeks later, "history | grep \#", and see my work notes - along with the relevant commands - available.

I used to write '~/bin' scripts for special stuff, including comments in the .sh source itself - but now it just makes more sense to wang a comment at the end of the complex/interesting commands and then just grep for the comment later ..


I have a similar system but take advantage of prefix-search rather than Ctrl+r

For commands that I reuse semi-frequently I set an environment variable so that I can easily find them with prefix searching. So for example I sometimes pin IPFS paths to Infura so I have this command in my history. I can then type pin=<Up> and recall that command (until it drops off the end of my shell history).

  pin= r curl -fiXPOST "https://ipfs.infura.io:5001/api/v0/pin/add?recursive=true&arg=$(c)"


Useful, but dangerous! I would have to check if there is already an environment variable in use before I did that ..


I know this command doesn't depend on a lowercase `pin` variable so there is no danger. Note that this doesn't change the variable in the shell, just the executed command.


Yeah, its the 'knowing beforehand' part that makes this dangerous for me. ;)

Cute trick though, will work it into my workflow and see how it feels.


IDK, environment variables get set all of the time, I rarely worry about them breaking programs. Their job is kinda to live in the background and be passed through programs so it doesn't feel like much danger. Especially when I use lowercase and almost all programs use uppercase.

But I guess everyone has a different risk level and what feels near-zero to me is meaningful to someone else.


I always add

  "\e[A": history-search-backward
  "\e[B": history-search-forward
to my .inputrc, I find it easier to use than C-r as it's some sort of autocomplete from history. But looking up commands with !number can still be very useful when you don't remember the command you need but remember when you used it (e.g. what commands you ran before and after).


What are the "\e[A" and "\e[B" do, are they key presses?

I usually do `history | grep ...` to find the command and then use it.

Non-emacs users might tend to find this surprising, but in a shell buffer you can move around with your cursor like in a text file, so after executing `history` you can search for the command as string then copy-paste it.


Yep, it binds history search to key up and key down. Start typing a command, press up or down and it will scroll through matching completions from history



Agreed. Much better than Bash's terrible built in ctrl-R which doesn't even show what you're typing if it doesn't match.


I've used build-in browser for years, but I highly recommend switching to https://github.com/junegunn/fzf for C-r in shell. Night and day boost.


Can you navigate C-r history, or are you forced to see only the last command?


Pair <C-r> with `fzf` if you want good ux.


I've noted once within my personal bash cheat sheet this:

Search the command history

* Search as you type: Ctrl + r and type the search term; Repeat Ctrl + r to loop through results.

* Search the last remembered search term: Ctrl + r twice.

* End the search at current history entry: Ctrl + j

* Cancel the search and restore original line: Ctrl + g

Try of course at your own risk. But works for me.


You can! If you do C-r again, then it will show the next command in your history for the given search.


If your are on a production server, it's more like a Russian roulette rather than lottery.


Real Russian roulette would be to preload history with a sure-shot such as `sudo rm -rf /`

If you don't like your job there's also the Polish variant, where you take one bullet out of every six.


I don't use the terminal often, but when I do, the feeling of sheer power and control over the system is palpable. I'm a fast and nervous typer, so I always try to slow down and notice all the ways I could lose data, and how easy it would be to make such mistakes (eg. how many mistyped letters away from wiping my database am I?).

Over time, I got better at noticing danger areas. Whenever I use 'rm', I re-read the command a couple of times as an extra precaution. Doesn't feel like that's enough.

I wish we had --dry-run for everything.


Regarding `rm`, I usually have something like this setup in my bashrc/zshrc:

    rm () {
        mv "$@" ~/.trash
    }
So any time I use rm, it actually just moves it to ~/.trash instead. Not fool-proof nor perfect, but have saved me at least once so found it to be good enough for now.


You might want to add a slash at the end of "trash", or add a mkdir before that command. Otherwise, doing this on a system where ~/.trash doesn't exist can still make you lose files after multiple deletions.


I use the `can` command. It does something similar. Personally, I find a separate command to be better so that I treat rm with kid gloves on new systems. https://github.com/joshvoigts/can


I'd be afraid of relying too much on this only to, at some point, be on a server or user that doesn't have this and accidentally deleting something too early.

Maybe it'd be best to just give this command a new name like `delete` or `trash` just to be safe.


> Maybe it'd be best to just give this command a new name like `delete` or `trash` just to be safe.

But this would defeat the original purpose, i.e. the prevention of someone accidentally using rm.


Not necessarily. If you get used to using `delete` all the time, that is most likely what you would use on the server too. Once you trip over it missing, you are reminded that you are in dangerous territory.


There are many assumptions here. I manage several servers, but many of these are co-managed. Second, it is not foolproof - muscle memory is very strong and for sure sooner or later I'll type rm again. Third, it doesn't prevents the use of rm in scripts.

That said, an accidental removal of files has never been a problem for me (an accidental chmod -R caused me more woes once), and these days with snapshots it's a complete non issue.


If you get used to using a different command, you won't use `rm` accidentally


Sure, but in the context of the present thread I'd have to wait until the history file gets rotated - which will never happen on the systems I manage.


just grep through your history file and delete lines containing `rm` easy fix


"echo" can be useful when prototyping scripts and for cycles, I prepend my critical commands (e.g. mv and rm) with echo and run the cycle to see all the commands with variables expanded before actually running them.


You need to enable magic-space: https://relentlesscoding.com/posts/bash-magic-space/ # this will automatically expand any variables and history when you hit the spacebar after them, so you can eyeball before running.

Someone tell me what the zsh equivalent is?


In zsh you just type !1234<tab> and it expands to the full command so you can review and edit :D


Not foolproof either, but

export HISTIGNORE="* rm *"

makes calls to rm not show up in the history, for better or worse.


I've added now both:

export HISTIGNORE="* rm *"

export HISTIGNORE="rm *"

I think it's even a bit better. Better preventing worst case if possible right from the start. And usually you don't need rm commands within your history. At least I don't.


Nice one and easy to apply, thanks! Just added it to my .bashrc


You can view the history (with the line numbers) by typing 'history'. If you have the following set, you can avoid any command prefixed with a space ever getting in this list. HISTCONTROL=ignorespace

I have trained myself, over many years, to hit space automatically before I type rm/reboot/shutdown etc. It's occasionally inconvenient if I need to rerun something but does mean I can't fat-finger anything destructive!


Never had an issue with this. Change your shell prompt to include the history line number. Remember, it's session dependent - if you have two simultaneous shells, the command number can be the same across both of them (so don't expect it to always work across different terminal sessions).


I never understood the utility of history substitution (I think this is what it's called). Why not just ctrl-r to see the actual command? Also, `sudo !!` thingy that is (was?) persistent in the internets for some reason, is probably the dumbest thing out there.


`sudo !!` is perfectly alright. It references the very last command, which in all likelihood is right there on your screen, typed by you a few seconds ago, and you're aware of the context.

$!(some number) instead is quite insane and much more likely to have unwanted effects due to (potential) lack of context.

Don't conflate the two.


I never used !! and similar. However my CLI is set to keep the cursor at the front when pressing <Up> to go through history (for easy prefix searching) so I can just use `<Up>sudo ` to get the same result and I like seeing the full command before I run it.


“alias ffs=sudo !!” Is cute though.


`sudo !!` is just very useful, just as most other things you can do with history substitution. Ctrl-R has its own usefulness but it only does a fraction of what history substitution can do.


I like fish shell's approach: [Alt]+[E] prepends the command with `sudo`.

So you hit arrow up to bring up the last command, then [Alt]+[E] to sudo-ify it.


Add a :p to the end. It’ll echo the command to the term and put it in the history so you can just up arrow. But it’s a no op


keep calm and `shopt -s histverify` on


Hey that's super cool, thanks! Works great!

For those who want to read about shopt, check:

http://www.gnu.org/software/bash/manual/bash.html#The-Shopt-...

Took me a bit to find it, and there seems to be no man entry.

Most important commands:

shopt -s histverify # activates the option

shopt -u histverify # deactivates the option

shopt # shows all available options and their activation status

You must put "shopt -s histverify" to your .bashrc so that it stays activated.


This is the best answer...

Well the one I use anyway.


Another fun fact: $!-x goes x commands back in history. Highly more useful I suppose :D


Lookup with the command history And execute with ![nn].


A lot of great suggestions here, thank you to everyone!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: