Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Some Useful Bash Aliases (2022) (chuck.is)
85 points by todsacerdoti on Dec 25, 2023 | hide | past | favorite | 79 comments


Protip: don't create aliases that override common commands (e.g. alias cp='cp -r'). Months down the road, you'll try to copy/paste some long piped command, and be confused as to why it works on everyone else's machine but not yours

Instead, create alternative commands, like alias lsl='ls -lah', and put in the work to make it the default thing you type.


I can't stress this enough. It will also kinda poison your intuition.


Don't paste long piped commands unless you know exactly what they do.


uhh, hmm. For thirty years or so I've lived by these two (shell immaterial):

mv='mv -i' rm='rm -i'

simple enough to add /bin/ to the command if I really mean it. That fixes the pipe issue too. I've had new to linux new hires go 'uh well I shoulda done that thanks I've done it now' more than once.


You can also do backslash to skip the aliases, e.g. \rm wouldn't ask for confirmation (skip the -i)


Or quote-wrap `'rm'`.


> Alias: rm > Command: rm -r Purpose: Because when I type "rm" I don't want to always have to specify "-r" for a directory. Alias: cp Command: cp -r Purpose: Same as above. When I say "copy this" I always want it to copy whatever I'm specifying, even if it's a directory.

This is insanely dangerous. Don't do this.


A way better solution is to alias trash-d as a drop-in replacement for `rm` : https://github.com/rushsteve1/trash-d


Also, ‘gio trash’ is widespread.


Never heard of it before, let's man gio :

    gio is a utility that makes many of the GIO features available
Ok, thanks I guess :D


What I mean is: a precept of command-line fluency is to be able to drop onto arbitrary systems and change them in ways predictable to the next sysadmin. ‘gio’ is a vague entry point to a library, and even if the next sysadmin doesn’t know about gnome, the files you trashed end up in a common recycling bin.

On the other hand, KDE has a syntax that deserves an alias.


Agreed. I like that you need to use '-r' ... it's that extra layer of safety and intention. A whole directory gone is a bit hard to recover from.


Do this in important directories for added safety: $ touch -- - i This creates a file called "-i" which will add the interactive flag, prompting you before deleting every file that rm was going to delete.


That seems flaky at best. Basically you rely on "*" expansion to inject the -i.

While that may work for `rm -rf *`, it won't for `rm -rf foo/*`, `rm -rf foo`, etc


That's the point. You're not relying on it, it's a safety to save yourself from an unintended glob expansion.


Or for far better reliability, just use safety and add that to the config.


Agree. (I actually feel the same way about aliasing rm to “rm -i“).

I depend on the out of box behavior of rm. I’ll run “rm *” in a directory that has subdirectories I want to preserve, but where I want to erase the files.


  alias ..='cd ..'
  alias ...='cd ../..'
  alias ....='cd ../../..'
  alias .....='cd ../../../..'
  alias ......='cd ../../../../..'
  alias .......='cd ../../../../../..'
Merry christmas, HN!


I used to do things like this until I found bash has

shopt -s autocd

which makes it so naming a directory cd's to it, including .. ~ etc.


I think it's a terrible idea, because one day you'll try to enter a directory that shares its name with a command you don't know, and it will execute this command instead


up() { cd $(eval printf '../'%.0s {1..$1}); }

So you can just type something like `up 2` to move by two directories.


eval printf? um.... is your name little bobby tables by any chance?


I devised `cdb` for this: https://github.com/jafarlihi/dotfiles/blob/a5133f49d67732199...

You can do just `cdb 5` to navigate 5 directories back.


Not bash but if you're using fish you can use https://github.com/nickeb96/puffer-fish


I did not realize cd'ing up was an esoteric sport. My own take:

  shopt -s cdable_vars
  u2=../.. u3=../../.. u4=../../../.. u5=../../../../..


I use numbers to avoid counting how many dots I am writing, just use 1. 2. 3. 4. to call these cd 1, 2, 3, or 4 levels up.


my version of ..

  function ..() {
    local temp_dir=$PWD
    cd ..
    for token in "$@"; do
      cd ..
    done
    OLDPWD=$temp_dir
  }
so you can just type .. to go up once or .. [word] to go up twice and so on


That seems potentially unpredictable versus building the string and calling cd once. For example, if you use direnv-type tools there may be side-effects along the route¹. zsh users could have state changing via the chpwd functions too, although that could be mitigated with "cd -q" at least.

Obviously, it might not be an issue for your use, but just noting a potential gotcha if I were to lift it for example.

[ Golf-y zsh, because vacation time and AoC has finished: ..() { cd ../${(pj:/:)${@/*/..}} } ]

¹ even just expensive setup/teardown delays would feel odd*


avoid disasters!

# -i: Cause mv to write a prompt to standard error before moving a file that would overwrite an existing file. If the response from stdin begins with 'y’ or ‘Y’, the move is attempted. (-i overrides any previous -f or -n)

alias mv='mv -i'

# -I: Request confirmation once if more than three files are being removed or if a directory is being recursively removed. This is a far less intrusive option than -i

alias rm='rm -I'


I always like to do 'ls <pattern>' to see what I'm blowing away, then CTRL-a CTRL-D x2 rm

Usually I know that I'm doing.

Also like 'rm -fv' because feedback is good.


There are few more general solutions to this interaction pattern(that also don't involve redundant history entries if you're OCD).

* bash has a glob-expand-word function which will perform inplace expansion of patterns, it is bound to C-x* out of the box. Using it will expand the pattern before point. Depending on the keymap you're using it is available via the same binding or the expand-word function in zsh too.

* C-xg (the glob-list-expansions function) will simply dump the expansion but retain the pattern in the command, if you'd prefer it didn't get added to history fully expanded for example. Again depending on keymap in zsh it is bound to the same key and calls the list-expand function.

* You can recall combinations of arguments from any line in history, so in your example 'rm !*' would recall all the args to previous command. The main reason this is useful is that you can also apply substitutions to fix incorrect results, and also because you can target other lines not just the previous one. You can even tack a modifier on to print the result without executing to double-double-check things, should you be feeling super careful(rm !*:p). zsh supports the same syntax, but has advanced more advanced modification options.


I have the same habit. I also use a somewhat similar "dry run" trick in `find` calls, such as:

    $ find foo/ -type f -name 'bar*' -exec echo rm {} \;


Yes, but I usually need to look up the -exec clause, because `{} \;` just feels hinky.


Modern versions has -delete as an option.


That is a GNU findutils extension, and modern means 2004 in this instance¹ ;) I spelunked because I thought "that always worked, didn't it?"

¹ https://git.savannah.gnu.org/cgit/findutils.git/tree/NEWS#n2...


Bash aliases for specific ssh hosts are seldomly needed, you can just as well configure hostname aliases in your .ssh/config file


Helpfully modern ssh, at least 7.x IIRC, can handle Include statements in the main config. You need to put includes before any host configs you have in the main config file lest it think the include is part of a host's configuration. But this makes managing cloud host configs for instance much easier.


I have aliases for zsh to quickly edit all my configs, it's pretty neat :

     declare -x -A configs
    configs=(
        gdb                "$XDG_CONFIG_HOME/gdb/gdbinit"
        git                "$XDG_CONFIG_HOME/git/config"
        vim                "$HOME/.vimrc"
        wezterm            "$XDG_CONFIG_HOME/wezterm"
        zsh                "$HOME/.zshrc"
    )
    for key value in ${(kv)configs}; do
        if [[ $key == "zsh" ]]
        then
            alias ${key}config="$EDITOR $value && source $value && echo 
    $configs[zsh] has been sourced"
         else
            alias ${key}config="$EDITOR $value"
        fi
    done
Just use zshconfig now if you need to add a new config file to the array and get a new alias


fzf is the final solution.


I like my alias

  alias cd-gitroot=cd "$(git rev-parse --show-toplevel)"


I use a variation of this to enable my conda environments - I always name the conda env the same as the top level git folder and can then quickly enable my env with an alias


Here's one I use pretty often: alias yt-dl="yt-dlp -f 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/mp4'"


I have almost the exact same but with "--restrict-filename" lest you end up with emojis and other Unicode characters you do t necessarily want on your file system.


I came up with this alias for xargs, I find it quite handy,

    # f# like |> pipelining, example `echo "~/.bashrc" |: vim _`
    # sed here is removing the last newline of the output
    alias ::='sed "$ s/\n$//" | xargs -I_ --'
Usage example, where `_` is a marker `::` (xargs) uses to swap in the pipe'd value

    sudo docker ps -a | skip 1 | col 1 |:: sudo docker rm _
skip, col are other aliases/functions,

    function col {
        eval "awk '{ print \$$1 }'"
    }

    function skip {
        tail -n +$(($1 + 1))
    }

    function take {
        head -n $1
    }


(cont)

I also quite like,

    function mkcd {
        command mkdir -p "$1" && \
        command cd "$1" && \
        pwd
    }
I'm thinking of writing one for git clone, `git clonecd` or something, to cd into a cloned directory. Note that having an executable named `git-foo` in your $PATH lets you call it like a git subcommand, `git foo`


Just don't alias `rm -r` to `rm`, it will bite you hard one day.

Use this instead : https://github.com/rushsteve1/trash-d


> I also have another alias which will SSH into my shared hosting, shortening ~70 characters down to just `sshchuck`.

You can also accomplish this by adding `chuck` to your `~/.ssh/config`. IMO it's better to do it that way because you don't break tab completion. Indeed, if your shell is setup for it you should be able to tab complete any entry in your SSH config.


I almost regret this one because of how often I use it on systems that I haven't set up yet:

    alias +x='chmod +x'


If you make it a file and put it in your $PATH, you can also invoke it from within vim for example.

I find myself using `!chmod +x` often from inside vim, so this will be quite nice, `!+x`

Edit: Sadly it doesn't work, trying to run `!+x %` in vim makes bash (my shell) treat `+x` like an option I believe.


I don’t believe the `![command]` syntax in vim command mode has access to the user’s aliases


You're right about aliases. But an executable in your $PATH does work.


Great idea!


I have one that activates the python venv in the folder I just cd-ed into.

Small problem: when I open a project in vscode, the terminal just opens already at the folder and doesn't trigger a cd.

So now I do `cd .` a lot and I don't remember off the top of my head how to activate a python venv anymore.


I have a bunch of directories I always go to, and instead of cd-ing on a relative path from where I am, I prefer using an interactive way to select where to go (I’ve aliased this script as “c”):

d=$(ls ~/Dev | fzf)

if [ -z $d ]; then return 0

cd "~/Dev/$d"


I rely on zsh and its search. Basically just type cd and follow it by enough characters to narrow down your search, then up arrow. History search has always surprised me seeing how I am mostly always doing the same thing. Things actually work before even needing to search manually since the history will suggest commands. (These use fairly well known plugins. I never use oh-my-zsh or any kind of plugin manager)


Why not just customize $CDPATH


Not quite the same but you should check out autojump if you haven’t before: https://github.com/wting/autojump


If fzf is installed fully, you’ll find Alt-C useful.


I love this sort of thing I always like to read about people's terminal usage, and the terminal programs.


These setups are intensely personal though and very limited applicability to anyone else.

And this particular example is dangerous and full of footguns. Cp, rm dangerous by default.

SSH can be just `ssh c` or `ssh chuckbox` with a proper ssh config.


Don’t forget a bunch of useful git aliases

alias gcm=git commit -m

alias gaugcm = git add -u && gcm


My favorite:

alias gfp=“git commit --amend --no-edit && git push --force-with-lease”

For those “whoops, for got to add $x file” moments or typos


I have basically that set up as gitconfig alias "git amen"


Yes and many more git alias commands at https://github.com/gitalias/gitalias


Here are the ones from my shell, accrued into muscle memory and my zshenv over the years:

alias ga="git add"

alias gaw="git add -A && git diff --cached -w | git apply --cached -R"

alias gb="git branch"

alias gbl="git branch -l"

alias gbD="git branch -D"

alias gbu="git branch -u"

alias gc="git commit"

alias gca="git commit -a"

alias gcaa="git commit -a --amend"

alias gcam="git commit -a -m"

alias gce="git commit -e"

alias gcfu="git commit --fixup"

alias gcm="git commit -m"

alias gco="git checkout"

alias gcob="git checkout -b"

alias gcoB="git checkout -B"

alias gcp="git cherry-pick"

alias gcpc="git cherry-pick --continue"

alias gd="git diff"

alias gd^="git diff HEAD^ HEAD"

alias gds="git diff --staged"

alias gl="git lg" # TODO - make these options defaults for "git log" itself

alias glg="git log --graph --decorate --all" # TODO - make these options defaults for "git log" itself

alias gdc="git diff --cached"

alias gpom="git push origin master"

alias gr="git remote"

alias gra="git rebase --abort"

alias grb="git rebase --committer-date-is-author-date"

alias grbom="grb --onto master"

alias grbasi="git rebase --autosquash --interactive"

alias grc="git rebase --continue"

alias grs="git restore --staged"

alias grv="git remote -v"

alias grh="git reset --hard"

alias grH="git reset HEAD"

alias grH^="git reset HEAD^"

alias gs="git status -sb"

alias gsd="git stash drop"

alias gsl="git stash list --date=relative"

alias gsp="git stash pop"

alias gss="git stash show"

alias gst="git status"

alias gsu="git standup"

alias gforgotrecursive="git submodule update --init --recursive --remote"


I use this zsh function and define my git alias in my git config.

    # No arguments: `git status`
    # With arguments: acts like `git`
    function g() {
      if [[ $# > 0 ]]; then
        git $@
      else
        git st 
      fi
    }

    # Complete g like git
    compdef g=git


    # Complete g like git
    compdef g=git
That's brilliant.


I have my zsh set up so that if I just press Enter without writing anything it will run ls -l or git status if it's a git directory.


How do you do that? Is it part of your PROMPT?


Sorry for the lag, I'll just drop the answer anyway in case it still can be helpful to you or anybody else.

It's actually a oh-my-zsh plugin, called "magic-enter".

I defined MAGIC_ENTER_GIT_COMMAND="git status" and then included the plugin.

You can find a different but similar plugin here: https://github.com/zshzoo/magic-enter/blob/main/magic-enter....


Neat, thanks!


I mentioned this in another comment, but checkout git's builtin support for aliases, defined in ~/.gitconfig [1]

And git lets you define custom subcommand if you just create a file like `git-foo` in your $PATH, and then you can run it like `git foo`

[1] https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases


alias h='history'

alias pst='ps -ef --sort=start_time'

alias rmgit='rm -rf ..?* .[!.]* *'


alias please="sudo"

alias amend="git commit --amend --no-edit"

alias vim="nvim"


For git aliases you should definitely checkout alises[1] you can define in your global git config, ~/.gitconfig, and the fact git will let you define custom subcommand if you create a `git-foo` executable in your PATH, for example, create a executable shell file called, `git-foo` somewhere in your PATH and you can run it like `git foo`.

[1]: https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases


vim="nvim" is wild


my cute favorite:

    curry='xargs -I{}'


I've got something, if you look at my comment on this page,

    sudo docker ps -a | skip 1 | col 1 |:: sudo docker rm _
Makes it look more like a functional language pipeline


oh super pretty




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

Search: