Hacker News new | past | comments | ask | show | jobs | submit login
Bash-Oneliners: A collection of terminal tricks for Linux (github.com/onceupon)
161 points by alexzeitler 5 months ago | hide | past | favorite | 62 comments



I so rarely see my (oft-repeated) favourite BASH script hack - commenting ones command lines:

    $ mv -n ~/Desktop/*.pdf ~/Documents/PDF_Archive/  #pdfsync
This command, which sweeps all the PDF files off my Desktop into a PDF Archive, is easily recalled with the key-combo Ctrl-R "pdfsync" - this is very convenient because it doesn't require me to add a custom shell script anywhere, in any particular path, and can also be used to refer to combinations of commands, for example:

    $ for i in some_collection_of_git_repos/ ; do ; pushd . ; cd $i ; git fetch --all ; popd ; done #refreshgits
Ctrl-R "refreshgits", and voila: all of the repos I'm interested in get a full automatic refresh ..

Command commenting is my favourite trick to teach ops newbies, too .. right after they learn about just how important "history > some_history.txt #historylog" is as a command, as well ..


At this point why not create an alias or function in bashrc? Then is also portable to other setups?


Although I do have plenty of real aliases, functions, and even whole shell scripts, keeping something as a spelled out command in history actually can be better in at least two ways: It's more flexible, and it's self-documenting.

Worked example: Sometimes I like to fall asleep listening to an audiobook or podcast. So I open termux on my phone, and run something like:

    sleep 10 && date && mpv --volume=90 --speed=1.2 $AUDIO_FILE ; date
which gives me a moment to settle in before it starts playing, leaves the start/end time on the screen so I have a rough idea when I fell asleep, and presets the audio how I like it. Now of course I could extract that into a shell function like `mpv-tweaked` or whatever, but that would either hardcode all the numbers there, or require me to implement arguments, and even if I did they wouldn't be as visible. By just pulling it up with ctrl-r and editing as needed, I have all the options visible right there and every one of them is obviously labeled.


Making functions takes substantially more effort (and has some advantages).


Easiest way I know of:

Ctrl+R to start reverse search

Type enough to locate last command

Ctrl+X, Ctrl+E to launch command in $EDITOR

Wrap in fn() {} or alias

Save as, or append to some file, e.g. in Vim `:w >> ~/.aliases`


.. promptly forget that you did this, or where you put the file containing the custom shell function, etc.

Ctrl-R serves a mnemonic purpose as well.. it helps you document your workflow and processes at the shell, and not hidden in some file somewhere.


Yeah if you can't locate code you wrote in your own home directory, I dunno what to tell you mate. I'm not here to tell you not to continue your love affair with reverse history search. Do what works for you. All I did was share the easiest way I know to persist a history item as a fn or alias.


Where does it live? In a .bashrc I have to maintain? The point is, not having to create an alias or function, because the tool lives in history.

None of these are that complicated that they deserve a dedicated shell script and chmod'ing, or presence in a cloneable repo, etc.


Tools that live in history are fine and good ... until they roll out of history.

Mind: I rely on shell history all the time, and I'm noting, admiring, and planning to adopt your commenting hack, it's ingenious.

But once a particular shell hack / one-liner / function has become sufficiently useful and proven, I'll typically add it to a shell function file (~/.bash_functions, sourced from ~/.bash_profile or ~/.bashrc), or my scripts directory (typically ~/.bin/ for personal hacks, /usr/local/bin/ if it's something I'll use from multiple accounts. Also park that under git and back it up / archive it somewhere or several somewheres.


Atuin should help with large histories; https://atuin.sh/

Graduating specific oneliners into functions/scripts is also a good chance to clean them up a bit, but it's a balance that's hard to strike - too many aliases and scripts, and you quickly forget they exist :-)


Thats fine, but do you understand the point that, by putting these utilities into a shell script, you're negating the ability to search for common commands through history, and now also need to load up your working memory with the name of the script, where it's located and so on?

I do put bigger/heftier utility functions into shell scripts - its just that I, more often than not, forget where they are and have to go searching. But with Ctrl-R, the flow does not get interrupted.

Anyway, not arguing for/against either technique - they are both appropriate when needed.


Commands which I make frequent use of as shell scripts or functions ... are also in my shell history, interestingly enough.

They also benefit by the further mnemonic / rediscovery trigger of existing in my local ~/.bin/ or ~/.bash_functions directory and/or file(s).


If you're not worried about multiple machines, then appending to bashrc is low effort. If you are, then jumping to version controlling at least part of your bashrc (just source it from the main file) is probably the easiest solution anyways. I agree that all of this is more effort than history, but only barely and I think it's worth it for common things that are suited to becoming functions or such


Note that you can use git-for-each-repo(1) to run git-fetch on a list of repos. You can define the list in your Git config and use that.


Thanks, yes I do know about that, but sometimes I want to have a bit more control over the for .. do .. end loop .. and also I'm rather a bit more of a fan of using the directory structure to remember repo's than a git config file somewhere, you know?


That's a good one! I didn't know the comments also showed up in reverse search. TIL!


I'd like to point out that, for example, Ctrl+a is not specific to bash, it's a readline[0] keybinding. A subset of those will work in the text box in which I am typing this comment. C-f and C-b work, even C-h, but not C-w. Perhaps this key combo is reserved for closing the firefox tab on windows? Anyway, I love readline and wish it would work on literally all text inputs.

0. https://en.wikipedia.org/wiki/GNU_Readline


Some points worth clarifying:

- Readline is not used in every text field by default. Rather, e.g. MacOS and Readline independently offer a subset of the Emacs keybindings by default (Emacs predates Readline by many years, and I believe Ksh was the first shell to start adding some Emacs bindings to its CLI).

- Many modern CLI apps don’t use Readline, although many of them imitate the default Readline keybindings. Notably, Zsh, Fish, and IPython all use their own line editors that are clearly Readline-inspired but still different. (IPython used to use Readline, but dropped it 5-6 years ago.)

- As other commenters mention, Readline keybindings can be changed: You can switch to Vi keybindings if you want, or define your own in .inputrc. But note that those settings only affect apps that actually use Readline under the hood, so e.g. Zsh and IPython require different settings.


Hear the gospel:

    $ set -o vi



POSIX specifically calls out "set -o vi" for any and all compliant shells.

The .inputrc is specific to readline, and will not be honored by libedit (used extensively on MacOS and BSD-centric systems).

"vi: Allow shell command line editing using the built-in vi editor. Enabling vi mode shall disable any other command line editing mode provided as an implementation extension. It need not be possible to set vi mode on for certain block-mode terminals."

The standard does not specify an emacs option.

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V...


Bash uses readline, so setting it in .inputrc would be sufficient for bash, but it will also get applied to other apps using readline like gdb. Setting an .inputrc also allows you to configure other niceties like colored-completion-prefix and colored-stats [0].

There's certainly no harm in doing both 'set -o vi' in shell rc and 'set editing-mode vi' in .inputrc

[0]: https://wiki.archlinux.org/title/Readline#Colorized_completi...


Well, the impact of .inputrc is going to hit anything else linked with it.

Your Postgres psql client will switch to vi mode, which might not be what you intended.

And if a day comes that dash gets linked to libedit on Debian/Ubuntu, only the POSIX standard command will have the desired effect.


Better still, /etc/inputrc

The three lines that go in the top of /etc/inputrc on my boxes:

    set completion-ignore-case on
    set editing-mode vi
    set keymap vi-command
For completion, I also set the following in the bottom of /etc/bash.bashrc

    export EDITOR=vi
    set -o vi


TIL


See also: Entering text in the terminal is complicated (https://jvns.ca/blog/2024/07/08/readline/) — being able to diagnose what's going on makes the command line feel a more predictable and less chaotic


I can warmly recommend making your own oneliners.txt over time, especially if you hop between boxes a lot. Some of the more hyper-specific entries in my own list has saved my bacon more times than I'd like to admit... https://ocv.me/doc/unix/oneliners/


Also related: bash_history is your best productivity tool; https://martinheinz.dev/blog/110

I have a weird story about that.

When I was a junior sysadmin I worked for a company providing a SaaS solution for e-commerce.

The environment I worked in was bare-metal (as was the style at the time), with a 2 tier network architecture, lots of internal tooling (mostly in Perl fwiw) and highly complex interactions between components (cache items recorded in MySQL, centralised job control through a pair of activeMQ servers that had a postgres proof of record etc).

During this time, I fancied myself the growing expert, and thus I created the most gnarly one-liners you could imagine. But they did everything. I annotated them with a “function parameter” comment at the end

    $ if []; then x; fi ## FUNCTIONDOES: THING
then I would control+R constantly from the bastion host to do my daily work. I had managed to automate a huge amount of common requests this way.

The existing team was disgruntled and started leaving, eventually making me the most senior in the team.

Of course, I also left.

I kept good contact with the team that onboarded as I was leaving, and one day while drinking I was told (off-handedly but in no uncertain terms) that I was the author of “the bash_history”.

After enquiring to what they meant, they indicated that after I resigned, someone found my bash_history file (because I had been onboarding them and they had seen my workflow) and it had been immortalised by:

A) Being copied to everyones profile and placed in /etc/skel

B) being chattr +i (immutable)

I was honoured. and horrified.


What is your definition of bare metal?


No virtual machines, zones/containers/jails.

Physical deployment with an operating system that ran on hardware directly.

The only management interface being the very anaemic out of band management controller.


If you don’t jump around a lot between boxes, having a large HISTSIZE can be sufficient: you can write inline comments after fancy one-liners, and use Ctrl-R to find keywords in the comments.

Another option is to make functions, aliases, or scripts as a way of saving those tricks. Not applicable to all tricks, but stuff like “embed all referenced fonts in a PDF file using `gs`” or “get me the ISO 8601 week using `date`” is way easier to use when you wrap it like this.


And if you spend some time answering questions on stackoverflow/reddit, it'll become interesting enough to publish books ;)


A guy I used to work with aliased "fuck" to "sudo" because he would frequently run commands that require sudo, but forget sudo, and being able to type "fuck !!" was far more satisfying than "sudo !!"


This immediately disqualifies the person from having operator duties, imho.


Previous discussion (2022) with 108 comments: https://news.ycombinator.com/item?id=31250275


I'd love to make a fish shell version of this but I'm far from advanced enough with fish, perhaps it's a good excuse to start learning professional fish(ing)


There's already commandlinefu.com



Starting off at the top, "sudo !!" doesn't work outside of bash/csh.

On BSD systems with a pdksh variant, "r" runs the previous history command.

On Debian/Ubuntu, dash doesn't implement this.

The list is problematic from the first entry.


As a fish shell user, I'd like to notice that "bash oneliners" and "terminal tricks" are not the same.

TFA mixes them freely, but makes it clear they're two different things, HN title kinda conflates them.


You are right in one sense, but it’s pretty clear that terminal tricks = shell tricks. Especially because there is no singular “terminal”.

And well, if you are complaining about “shell tricks” not including fish.. you’re the one choosing to make a breaking change with the shell world at large. Can’t then go out in the world and complain about it.


As an aside, do you know why fish doesn’t support using !!

I generally like it a lot but this is one shortcut I miss


They recommend using keybindings instead of adding syntax for such interactive-only tricks. In this case, I think alt+up was the default Fish keybinding. (I think in Bash, alt+. does the same?)


What does TFA mean in this context?


The (Freaking|Fu**ing|Fine|Founding|First) Article.

A way of referencing the article that has been submitted and these comments are discussing.


Probably one of the most useless and pointless TLA I've come across so far. TIHI.


It derives from an expression deep in the history of Usenet or e-mail (hyphenated), when hapless newbies (two syllables) were told by harried sysops to RTFM, read the f* manual.


And while it is being used now to simply reference the article, RTFA was originally used in the same way as RTFM. A way of expressing frustration to a commenter who should have read the fucking article first.


Indeed. I usually go with “OP” in non-frustrated contexts, myself.


The Featured Article. I think it is a HN term?

typical usages: https://hn.algolia.com/?dateRange=all&page=0&prefix=true&que...


We were using the acronym back on Chips and Dips.


Fwiw, Ctrl+l is not the same as clear. clear will exit with code 0, Ctrl+l will not exit with any code.


I think it's "insert page break", technically and scrolling down the terminal is a result of that. "clear" actually clears the screen and the scrollback.


I have a small section in my regular training for fresher developers where I teach shell. I sometimes wonder if it's needed anymore.


Not needed because they typically know as much already, because knowing how to use a shell is no longer useful?


Second I assume. It's frustrating how little my peers care about the magic of the shell.


Presenter: I have changed this ten-line function to `xbdbwhh%¢|=€=%[©=¢==33` which is much shorter. It crashes for inputs that have four consecutive letters "j", but we don't have inputs that four consecutive letters "j".

Audience: Why on Earth would you do this

Bash community: FUCK YES


Well, what do they use instead?


VsCode, some git GUI and whatever command they can copy/paste from the docs to run the project. Understanding the why isn't important. This means they stagnate and don't explore further, they don't even understand how much can be done with coreutils and pipes.

To them the terminal emulator is for installing packages and running projects. Just trying to get them to use aliases is impossible and to them I'm a showoff for actually liking vim.


so much of the orchestration for servers that we greybeards had to for our unixen back in the day was shell script-based. nowadays its puppet or terraform or ansible or capistrano or [...]


Recently I have found that claude sonnet 3.5 is extremely good at coming up with bash one liners that do what you ask for fantastically.


Please be extremely careful blindly trusting oneliners from GPT's! Plenty of horror stories, but I'll name a recent one as example:

Someone wanted to use FFmpeg to (losslessly) convert video files from one container to another and then delete the original. ChatGPT made a script which created a list of filenames and passed them into a loop which executed ffmpeg on each file. Thus it ran headfirst into several edgecases, for example how FFmpeg by default (unless you -nostdin) consumes stdin byte-by-byte, which messed up the list of filenames. Of course it appeared to work fine, as it clearly was processing a bunch of files.

Secondly, it forgot to map the input streams correctly, so several files came out with subtly missing tracks.

But more crucially, it failed to check the returncode for each file, assuming everything went fine... And deleting the lone copy of several files which failed to convert. Of course there were no backups.

So if you must rely on GPT's, then do so with extreme caution. Don't get fooled by their "self-confidence".




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

Search: