Hacker News new | past | comments | ask | show | jobs | submit login
ZSH Aliases (thorsten-hans.com)
388 points by thorstenhans 45 days ago | hide | past | favorite | 105 comments

> I do a lot of conference speaking; if you are presenting at conferences or meetups too, you should start your presentation by quickly explaining the aliases you will use throughout the talk to onboard your audience.

If you're giving a presentation, please give the actual commands people need to type, even if that's a little more typing for you. There are tools to help you auto-type each line of a demo, if needed. Reduce the amount of confusion and translation people need to go through to understand your presentation.

Similarly, turn off any fonts that create symbolic ligatures, so people know what symbols to actually type.

Avoid anything unnecessary that increases the distance needed for understanding between you and your audience.

I think Fish shell "abbreviations" [1] are more suitable for interactive demos than standard Bash/Zsh aliases. Basically, instead of e.g. `gc` meaning `git commit` (alias), `gc` can be expanded to `git commit` (abbr), so you can save typing but still show the actual command.

Modern versions of Fish has both abbreviations and aliases. Personally, I prefer aliases for providing default arguments to commands (e.g. turning on colorized output), but prefer abbreviations for timesavers like the `gc` above.

[1]: https://fishshell.com/docs/current/cmds/abbr.html

Is there a way to get such expansion functionality for zsh? I would always use it, not only when demonstrating something but don’t want to switch to Fish only for that feature.

For suffix aliases, you can bulk them

  alias -s {ape,avi,flv,m4a,mkv,mov,mp3,mp4,mpeg,mpg,ogg,ogm,wav,webm}=mpv
as opposed to defining them one at a time.

I can't believe I got all the way through @scriptingosx's book on Zsh and the suffix aliases just went right over my head.

(Self, you idiot)

cd'ing into a directory on the fly without even thinking about paths and just opening files by name is powerful juju

Together With AUTOCD, this feels like it shouldn't be possible...but it is.

thanks for pointing me to this one. I've added a corresponding sample.

Is it possible to get zsh to just open all non executable files with xdg-open?

I use these suffix aliases to open programs occasionally.

    alias -g G='| grep'
    alias -g R='| rg'
    alias -g L='| less'
    alias -g V='| vim -'
    alias -g S='| subl'
And if I want Zsh to auto-expand it out to type the full command (after pressing space), add this to end of your .zshrc:

    globalias() {
        if [[ $LBUFFER =~ '[A-Z0-9]+$' ]]; then
            zle _expand_alias
            zle expand-word
        zle self-insert
    zle -N globalias
    bindkey " " globalias # space key to expand globalalias

Identical examples:

    grep -rw --exclude-dir={test,build} 'throw' L
    grep -rw --exclude-dir={test,build} 'throw' | less

The "navigation aliases" IMHO are better handled as ENV vars.

The example

    alias dev="cd ~/dev/"
    alias personal="cd ~/dev/thorstenhans"
    alias business="cd ~/dev/thinktecture"

    export dev=~/dev
    export personal=~/dev/thorstenhans
    export business=~/dev/thinktecture
And now thanks to the way ZSH handles directories, you can still simply change directory with

    $ ~dev
    $ ~personal
    $ ~business
and it'll work as before but it also allows you to treat it as a fully qualified directory in other commands which I find exceedingly useful

    $ tree ~dev
    $ cat ~personal/index.html
    $ rm -rf ~business/secret-documents

You can directly create named directories with `hash -d`. Eg.

    hash -d dev=~/dev
    hash -d personal=~/dev/thorstenhans
Nothing else is needed.

I'd argue environmental variables have the strong advantage in that you can use them in cases that won't otherwise expand, namely programs that take a path parameter immediately following an equals, e.g.

    $ docker run --workdir=$dev foo
in these cases `--workdir=~dev` is not expanded and fails as docker does not understand your alias.

True and I often have both. I like my exported environment variables to be all caps and my directory aliases to be lowercase. This keeps their uses separate.

I'm too lazy to shift-tilde

suffix aliases do not even have to refer to a real existing file. They are an alias. That's what I use to clone git repos I copypaste:

  alias -s git="git clone"

That is brilliant. Thanks mate.


happy hacking :)

wat? doesn't this prevent you from doing anything else w git?

This allows you to enter

Into your shell, and have it automatically get translated into

  git clone https://github.com/zsh-users/zsh.git
It has no effect at all on your ability to run regular git commands.

No, this really only addresses the situation where the URL ends with (suffix) “git”.

The only time I use the full URL is the initial cloning, and the remote name thereafter. But if you use the full URL in another scenario, yes, this may interfere.

As others commented, this only acts when the first word in your commandline ends with '.git'.

    - "git", alone isn't going to be hooked.
    - you can do "cd .git".
    - even if you have 'autocd' option set, you can '.git' and it will do "cd .git".
I'm not saying it's even a good practice, but I find it kinda cool, when using this feature in a way it's probably not intended for, you start thinking in 'what might happen inside'.

I don't believe so since I think suffix aliases are only affected by the "file extension" of the command you've added. The suffix alias in the OP is saying that if they paste something that ends with ".git", then clone that thing (i.e. if you paste the git url for a repo, it clones it). It doesn't overwrite the git command


Overwriting a command-line tool with no other arguments seems like a bad idea.

I use global aliases a lot, especially for pipes I use often. my main ones:

- alias -g G="| grep " (`cat test.txt G some_words`) - alias -g CC="| pbcopy " (`cat test.txt CC`) - alias -g "?"="| fzf " (`ls -l ?`) - alias -g X="| xargs " (`ls -l X rm`), probably my favorite (makes xargs kinda look like a pipe) - alias -g Y="| yank "

They compose well, too.

- Pick some file to delete from `git status`: `git status Y X rm`

I also love them global aliases! To push them even further (like the xargs one), I have those aliases to allow me to do quick iterations in 'streaming' fashion:

    alias -g FORI='| while read i ; do '
    alias -g IROF='; done '

Which "yank" package are you using? I came across one [0], which copies the file selected to the clipboard instead of outputting it to stdout. I managed to get it to print to stdout, though:

  alias -g Y="| yank -- cat "
[0] https://github.com/mptre/yank

that's the one, from the readme: "If stdout is not a terminal the selected field will be written to stdout and exit without invoking the yank command"

Could be clearer, basically it means that if it's part of a pipe, it's going to print to stdout instead of copying to the clipboard

> Use alias to edit and reload .zshrc

> source $HOME/.zshrc

.zshrc isn't the only startup file, if you place everything there you're likely doing it wrong and should split things like some environment settings to $ZDOTDIR/.zshenv.

Better way to reload startup changes:

  alias reload='exec zsh -l'

I have this reminder in every `~/.z*` file:

  # Load Order    Interactive  Interactive  Script
  # Startup       Only login   Always
  # ------------- -----------  -----------  ------
  #  /etc/zshenv       1            1         1
  #    ~/.zshenv       2            2         2
  # /etc/zprofile      3
  #   ~/.zprofile      4
  # /etc/zshrc         5            3
  #   ~/.zshrc         6            4
  # /etc/zlogin        7
  #   ~/.zlogin        8
  # Shutdown
  # ------------- -----------  -----------  ------
  #   ~/.zlogout       9
  # /etc/zlogout      10
  # Note: ZSH seems to read ~/.profile as well, if ~/.zshrc is not present.

> ~/.zshenv

Technically it's $ZDOTDIR/…

Also note from the official documentation:

> `.zprofile' is meant as an alternative to `.zlogin' for ksh fans; the two are not intended to be used together

I tend to use:

  alias reload="exec -l $SHELL"
Which I copied from somewhere, I don't know how specific it is but maybe it helps someone :)

Using $SHELL is not great because it is not a reliable env var. It's only set for login shells, and if your login shell isn't zsh you'll get a different shell on this "reload". (A long time ago I had an account somewhere where my sysadmin didn't respond to chsh request for whatever reason, so my login shell remained /bin/bash while I actually used zsh day to day.) It can also be anything, really:

  export SHELL=/sbin/nologin  # or /usr/sbin/nologin, or equivalent on your system
  exec -l $SHELL
You want zsh, so just use zsh.

As for -l, exec zsh -l and exec -l zsh both replace the current shell with a login zsh, so they are effectively the same.

Good point. Separation of different config aspects is in the pipe as dedicated article

Okay this is pretty cool, I can set up so `.js` files are opened automatically with Node.js:

    $ alias -s js=node
    $ echo "console.log('Hello world')" > demo.js
    $ demo.js
    Hello world

This seems like a good way to accidently run abitrary code downloaded from the internet.

I can see opening up in an editor as useful shortcut. But actually executing code without an executable bit seems a bit more dangerous.

Worse, imagine if someone set their shell as the suffix alias for .sh, just to save time on their curl shell pipes... Oh the horror. Suffix aliases should come with a big caveat.

Don't worry. I got you.

    alias -s sh='_c(){ curl -sk $1 | sudo bash };_c'
Wait. Improved.

    alias -s sh='_c(){ [[ -f $1 ]] && sudo bash $1 || curl -sk $1 | sudo bash };_c'

Really? Last time I downloaded a .js file by accident was never if my memory doesn't fail me (.html I remember a couple). Even if I did, I normally use the UI to manage my files. The only time I might try to do something with the CLI and a JS file is exactly to run `node file.js`, and this is just a convenience.

You can do something similar with a shebang and chmod +x.

...and even in a safe way.

But then you need the cooperation of every file to include the shebang line. Muuch easier to just

    echo :js:E::0::/usr/bin/node: >/proc/sys/fs/binfmt_misc/register

Yes suffix aliases are super useful

If you "override" a command in your PATH with an alias, you can access the original command with a leading backslash.

For example, I use:

``` alias open=xdg-open ```

To call the real open command, I can use \open.

That's a POSIX rule. Quoting any part of a word affects the entire word and thus preventing expansion. You can also write open''

Speaking of ZSH: it is the thing I miss the most in Windows (especially with ohmyzsh, and its plugins zsh-autosuggestions and zsh-syntax-highlighting).

I know that there is oh-my-posh, but it lacks such plugins. Do you know any workaround?

This can get you a part of the way, extracted from my PowerShell profile:

    # PSReadLine, see https://github.com/PowerShell/PSReadLine

    ## behaviour of Tab key autocomplete
    Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete
    ## From docs:
    ## With these bindings, up arrow/down arrow will work like PowerShell/cmd if the
    ## current command line is blank. If you've entered some text though, it will
    ## search the history for commands that start with the currently entered text.
    ## Like zsh completion.
    Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
    Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
These will allow you to autocomplete previous commands from the tidpids you already types, so it no longer searches linearly through the history. I also use:

    Import-Module posh-git
    Import-Module oh-my-posh
    Set-Theme Agnoster

Do you happen to have your PowerShell profile in a GitHub Gist or so?

No, but mostly because it is not much longer than the above! Only got started using PowerShell more seriously (thanks to Windows Terminal and WSL) a couple of months ago.

Here is the other content:

  # For Agnoster theme, "user@host" will be hidden if user==DefaultUser
  $DefaultUser = "<YOUR USERNAME>"

  function vim ($File){
      bash -c "vim $File"

  New-Alias pi ipython

  # git diff output uses less; it will be buggy without utf8

  # console output, e.g, when writing git diff output to file using pipe: | Out-File
  [Console]::OutputEncoding = [System.Text.Encoding]::UTF8

Is using WSL an option for you? I'm using oh-my-zsh with it just fine.

Without GPU support, not much.

unfortunately not. Sorry

My personal favourite

alias -g NF='./*(oc[1])'

This points to the newest file/dir in my current dir, and it is very easy for me to untar a downloaded file and then cd into it without caring about the name of the file/dir.

tar xf NF; cd NF

'C-x m' pulls the newest file for me:

mv ~/Downloads/[C-x m] /tmp

or even within files that match what I've typed already:

tail /logs/pho[C-x m]

Also worthwhile investing some time in the completion system if you are writing aliases to save time. I've done it for serverless invoke/deploy/logs and they've been so useful!

What I'm talking about is typing 'sls logs <tab>' and having tab completion for the deployed functions when typed in the root of the repo containing the serverless.yml file.


I love ZSH + Oh My ZSH. And I didn't even have a choice.

At my first company, the onboarding script included switching to ZSH+OMZ. I knew it changed the shell, but thought it was just theming - not much. A year later, switched companies, didn't install it. Don't know how I lived without it. It is such an amazing productivity update to shell life I consider it a must on every machine.

If you're working with Python projects and Virtualenv then this is a great alias to have (assuming you call it venv):

  alias venv=". venv/bin/activate"
Just cd to a project root and venv :)

I do something similar, although I use venv to create a new virtual environment and update pip and setuptools:

  alias venv='python3 -m venv venv && source venv/bin/activate && pip install --upgrade pip setuptools -q'
And then ae and de to activate/deactivate a venv:

  alias ae='source venv/bin/activate'
  alias de='deactivate'

The `cd ...` aliases are an interesting choice; I find it more practical to use `autocd` in combination with named directories.

  setopt autocd
  hash -d dev=~/dev
Now I can just use `~dev` to `cd ~/dev` but I can also do `~dev/foo/bar/baz` etc.

I have fallen in love with `z`

e.g. `z p` might take you to ~/projects if you've been there recently.


Good point, I'm a huge fan of `fasd` which provides similar features. I feel lost in a shell without `z` now!


Similarly, project autocompletion for the directory where I do my web dev ...

  export SITES=$HOME/Sites

  # Plural to cd and list contents
  alias sites="cd $SITES; ll"

  # Singular to access a particular project
  site() { cd $SITES/$1; }

  # Autocomplete function
  _site() { _directories -W $SITES -/; }
  compdef _site site

It works from within any directory, which is nice.

  site f[tab][enter]
takes me to


Does this work backwards, too?

For example if I'm in "/Documents/Dotfiles", but want to go to "/Documents/Blog". Doing the "../" dance is tedious as hell.

Sigh, again, I should have looked this up...

% Documents/Dotfiles

[~/Documents/Dotfiles] % ../Blog

This does the trick.

'z' should work well here - 'z D B'

Brb. I’m going to add suffix aliases for all of my frequently used code file extensions. I had no idea those are a thing.

Although I do wish I could pass a flag that didn’t open it, as sometimes I do want to append or overwrite a file without the fuss of an editor.

I don't think you're going to have a problem. The alias only affects you trying to "run" the file.

% foo.jpg

# launches image viewer

% cp foo.jpg bar.jpg

# unaffected

About suffix aliases, shouldn't one resort to file associations instead, and use the corresponding command (possibly with an alias)? It seems weird to have these settings stored in two places, and have inconsistent results when you open from the terminal and from another application (like a file browser).

What's the benefit of suffix aliases compared with setting up the associations? You only save two keystrokes if you have a single-letter alias (for xdg-open on linux).

Nice article, on ZSH too (oh-my-zsh). Real productivity.

BTW. Anyone is really using the colorscheme like in article ?


I wish I would chain things in the navigation alias.

For example if I set the following alias:

    alias hello = '~/Docuemnts'
It would be nice if I could then execute hello/world to take me to ~/Documents/world but it requires hardcoding.

Guess I could play around with functions and arguments to solve this.

I think I might be able to help with this one! Here's a little trick I learned from a friend. It's also tab completable.

I keep all my code in ~/code

$ c # cd to ~code

$ c pr<tab> # tab complete to c projectname

$ c projectname # cd to ~/code/projectname

This is pretty simple in zsh

# c to cd to ~/code

c() { cd ${CODE_DIRECTORY}/$1; }

# tab complete c against code

_c() { _files -W ${CODE_DIRECTORY} -/; }

compdef _c c

(Note: CODE_DIRECTORY is just an env var for ~/code)

I use this all the time and I use h to do the same for my home directory


No need for an alias, a variable (I think that's what they're called) will do:


    cd ~hello/world
Or omitting `cd` (requires `setopt auto_cd`):

And with `setopt cdable_vars`:

This also works with tab completion:


With ZSH, you can use a named directory hash to create such 'aliases' to directories:

    hash -d hello=~/Documents
The shortened names also show up in your PROMPT if it is using %~ to display cwd.

fish abbreviations kinda do this, for example if you define your alias above as an abbrev and you type hello<space>, it replaces hello by ~/Documents in your command line. You still have to press backspace to remove the space you just inserted, but it's better than nothing.

Also, apparently you can add this to zsh with a plugin: https://github.com/momo-lab/zsh-abbrev-alias

fish-shell abbreviations are really cool, I do miss that in zsh, I'll probably give that plugin a go. It also makes it for other people easier to see what's going on when looking at the previous commands.

add hash command in your $zshrc

  $ hash -d hello=$HOME/Documents
  $ cd ~hello/world && pwd

Any benefits to switching to ZSH in Catalina? The prompt every time I open the command line is annoying me

After avoiding it for a long time, I recently switched to ZSH with oh-my-zsh and I really like it.

But if you're not ready to switch yet and still want to use bash for now, set this to remove the deprecation warning:


Ah thanks

If you add a suffix alias, will zsh start offering to complete matching files as though they were executable?

If you use oh-my-zsh, the kubectl and docker-compose plugin provide good aliases for every command.

My favourites:

    alias ls='exa -l'
    alias gits='git status'

May I humbly recommend just including the git status in your LS command.

  alias ls="exa --color auto --all --group-directories-first --long --group --header --modified --sort=name --git --time-style=long-iso --classify"
That should give you a gorgeous directory list.

Use git aliases!

    # ~/.config/git/config
      s = status
      d = diff
      ds = diff --staged

    # ~/.zshrc
    alias g=git

    $ g s
    $ g ds
I think I have an alias for every letter of the alphabet.

my version of `gits` is `gs` :)

You can, also, add flags to your program:

  alias -s txt='less -rE'

I feel a bit misled that two of the "five types of aliases" are functions and regular aliases a second time.

Tldr: 1. aliases, 2. suffix aliases, 3. global aliases

Well, first I thought about publishing 4 types (I see functions as a valid kind of alias)

However, the os-specific aliases became more and more important to me due to GitHub and VisualStudio Codespaces. Targeting different operating systems is quite important to me.

But technically it's just a regular alias. (Which is also mentioned in the corresponding paragraph)

>This article will teach you how to create and use these four types of aliases

>You have seen four different types of ZSH aliases that will boost your productivity

`four` in these two lines is typo or intentional? Because the title says `5 Types Of ...`

thanks for the feedback. I've updated the corresponding parts

This caught my attention too. A cursory search of the zsh docs don't mention functions being a type of alias. In particular:

> The registration of aliases with parameters looks pretty similar to a function definition in regular programming languages.

Well that's because it is a function definition in this programming language, no?

Furthermore, this breaks down when you, say, use `alias` to view all your aliases. It won't show the functions, because they are not aliases.

i think one of the main advantages of zshs aliases (compared to bash aliases) is autocompletion, so I would not count regular functions as a kind of alias. But I can see the similarities.

alias rm=trash

I have a habit of cleaning up the workspace in my machine. This alias saved me a 1000 times already.

I prefer something like "alias sp=trash" (sp for suppress), and getting into the habit of using this alias (for instance by doing alias rm="echo nope"), so that if I use it on another machine by mistake, it just fails instead of using /bin/rm (and I can then resort to trash or double-check that my rm command is not faulty).

The actual link for this submission is


if your ad blocker is barfing on whatever bitly-based tracking doodad was submitted instead.

using aliases is a beginners mistake. they will one day break. just type in the real thing.

also, if you use aliases for commands that you use a lot, it is better to remember how to correctly type the command.

Wow I really can’t disagree with this hard enough.

I’ve added extensive aliases to my shell and it saves me mountains of time. If they break, so what? You fix them? It’s computers; everything breaks eventually.

I’m appalled at the idea of trading constant convenience against some hypothetical and unspecified future breakage.

Imagine writing software instead of doing everything by hand! That software could just break one day!

I don't understand what the negatives of typing `gs` over `git status` is.. Unless I have a bin named `gs`.. but as long as I know that, what are the disadvantages?

imagine not typing out the full/basic git commands the rest of your life and all the time that'll save though

imagine loosing your aliases. just learn to type and enjoy life.

Or you can spend less time typing and enjoy life

yes, but with a crutch

The worst case scenario is that I lose my .zshrc file and have to google commands again

Or, keep your dot files in a public/private Git repo and don't worry about that either. Also makes setting up new machines/users a breeze.

Yeah why would anyone not version control their dot files

How do you "lose" your aliases?

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