1. 44

What are the most useful aliases or functions etc for bash that you’ve collected or written? Or bash scripts. Please give explanation/usage if necessary. Ones you actually use often. Thanks!

  1. 17

    A really useful thing is to always display the error code unless it’s 0. Got used to it real quick and don’t know how I lived without it.

    prompt_show_ec () {
     # Catch exit code
     ec=$?
     # Display exit code in red text unless zero
     if [ $ec -ne 0 ];then
      echo -e "\033[31;1m[$ec]\033[0m"
     fi
    }
    PROMPT_COMMAND="prompt_show_ec; $PROMPT_COMMAND"
    
    1. 4

      Good point! I also have a prompt function for it, in zsh (screenshot: https://files.emnace.org/Photos/prompt-exit.png):

      ### EXIT
      ### prints last exit code
      ### but only if non-zero
      colored_exit_code() {
        echo "%(?..${nl}%F{8}exit %F{1}%?)%f"
      }
      custom_prompt_exit='$(colored_exit_code)'
      
      1. 1

        Indispensable for prototyping and shell scripting.

        I also like some of the oh my zsh themes and the like that will color code this for you as well.

      2. 11

        A couple small ones I’ve made:

        • boop plays a happy sound if the previous command exited successfully (i.e., exited with status code 0) and a sad sound otherwise. For example, if I’m running a long-running test, I might run npm test ; boop. It helps me know whether something finished, and whether something went wrong.
        • tempe creates a temporary directory and cds into it.

        I use these many times per day.

        1. 3

          On a similar note, I have this in my .bash_profile (Mac):

          function alert_if_not_in_foreground {
              if ! lsappinfo front | xargs lsappinfo info -only name | grep 'Terminal' > /dev/null; then
                  printf "\a"
              fi
          }
          PS1='$(alert_if_not_in_foreground) ... more stuff ...'
          

          So when I leave some long-lived command running, and by the time it’s finished I’m not looking at the Terminal, it prints the bell character (which on my setup will also make the Terminal.app icon bounce and show a notification badge) so I don’t need to remember to check it periodically.

          I guess it could be done with PROMPT_COMMAND as well, which this thread just taught me about :)

          1. 1

            Looks like a good idea. Where does that sfx command comes from though?

            1. 2

              Right here. It’s basically just a wrapper around mpv.

              1. 1

                Which sound files are you using?

                1. 2
          2. 11

            Oh, I have quite a few!

            For shell aliases and functions:

            vg: Shell function to open grep results directly in Vim using the quickfix. A bit of expounding here, in a small blog post.

            • rg foo (with ripgrep) to simply view results
            • vg foo to use the results as a jumping point for editing/exploring in Vim.

            A ton of aliases to shorten frequently used commands. Few examples:

            • When I want to sync a Git repo, I run gf to fetch, glf to review the fetched commits, then gm to merge. git pull if I’m lazy and want to automatically merge without reviewing
            • glp to review new local commits before pushing with gp. Both glf (“git log for fetch”) and glp (“git log for push”) are convenient because my shell prompt shows me when I’m ahead or behind a remote branch: https://files.emnace.org/Photos/git-prompt.png
            • tl to list tmux sessions, then ta session to attach to one. I name tmux sessions with different first letters if I can help it, so instead of doing ta org or ta config, I can be as short as ta o and ta c

            Also, “aliases” for Git operations that I relegate to Fugitive. Technically these are shell functions, but they exist mostly just to shorten frequently used commands.

            • Instead of gs for git status, I do vs and open the interactive status screen from Fugitive (which after a recent-ish update a few years ago, is very Magit-like, if you’re more familiar).
            • When I’m faced with a merge conflict, I do vm to immediately open Vim targeting all the merge conflicts. The quickfix is populated, and I jump across conflicts with [n and ]n thanks to a reduced version of vim-unimpaired.

            For scripts:

            First off, an easy way to manage my PATH scripts: binify my scripts so they go into PATH, binedit if I need to make a quick edit.

            ez: Probably my favorite one. A script to run FZF, fuzzy-find file names, and open my editor for those files. Robust against whitespaces and other special characters. I also have a short blog post expounding on it.

            watchrun: A convenience command to watch paths with inotifywait and run a command for each changed file. For example, watchrun src -- ctags -a to incrementally update a tags file.

            notify-exit: Run a command and shoot off a libnotify notification if it finishes (whether with a successful exit code or not). I have it aliased to n for brevity (using a symlink). For example, n yarn build to kick off a long-running build and be notified when it’s done.

            • Also, a remote counterpart rnotify-exit, which I have aliased to rn (using a symlink). For example, rn ian@hostname yarn build on a remote machine (within my LAN) to kick off a build, and have it still notify on my laptop.

            And a slew of scripts that are a bit more integrated with tools I use, e.g.:

            I normally keep these in fixed locations, so everything I’ve accrued naturally over the years should be here:

            1. 4

              I used to have a ton of these git shortcuts but at some point I threw them out again because I kept forgetting them. The only thing I use daily is git up which is git pull --rebase.

              1. 1

                I had a similar problem and only kept branch-history which showed me the one line commit diff between my feature branch and dev.

              2. 2

                notify-exit: that’s one of those ideas that is so great you facepalm and ask yourself why you never thought of it before. I’m adding this to my config tomorrow.

                1. 1

                  ez, is great, thanks for sharing!

                2. 10

                  After every command that takes more than 10 s, I display the elapsed and finish times. This requires bash 4.4 or later.

                  timer_file=`mktemp -t bash-timer.$$.XXXXXXXXXX`
                  begin_timer () {
                      date +%s%3N > $timer_file
                  }
                  PS0="$PS0\$(begin_timer)"
                  end_timer () {
                      local begin=$(cat $timer_file)
                      if [ -n "$begin" ]; then
                          local end=$(date +%s%3N)
                          local elapsed=$[$end-$begin]
                          if [ "$elapsed" -ge 10000 ]; then
                              local ms=$[$elapsed%1000]
                              local s=$[($elapsed/1000)%60]
                              local min=$[($elapsed/60000)%60]
                              local h=$[$elapsed/3600000]
                              printf '\e[35m%i:%0.2i:%0.2i\e[2m.%0.3i %s\e[0m\n' $h $min $s $ms "`date -d @$[$end/1000] '+%F %k:%M:%S'`"
                          fi
                      fi
                      echo > $timer_file
                  }
                  PROMPT_COMMAND="$PROMPT_COMMAND end_timer;"
                  before_exit () {
                      rm $timer_file
                  }
                  trap before_exit EXIT
                  
                  1. 1

                    Why do you store the timestamp in a file rather than an env var? Maybe relatedly: how does this not break if you do something like sleep 20 &; sleep 15 &? I’d expect them to share $timer_file so the second command overwrites the filename for the former.

                    (Also, thanks for this and your exit code comment, I have been idly wanting both features in my shell for years.)

                    1. 1

                      PROMPT_COMMAND executes before printing the prompt, so background jobs will not be timed. I wanted to use an env var but had trouble getting it to work, so if you do, please let me know!

                  2. 7

                    The ability to recall commands from the history, quickly.

                    First, keep a large and deduplicated history that is shared across all open terminals in real time.

                    https://github.com/dkozel/dotfiles/blob/master/home/.bashrc#L17-L22

                    # Maintain a merged history across all shells
                    HISTSIZE=5000
                    HISTFILESIZE=-1
                    HISTCONTROL=ignoredups:erasedups
                    shopt -s histappend
                    PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"
                    

                    Then remap the up and down arrow keys to search the history using the currently entered command (up to the cursor) as the search term.

                    https://github.com/dkozel/dotfiles/blob/master/home/.inputrc

                    "\e[B": history-search-forward
                    "\e[A": history-search-backward
                    
                    set completion-ignore-case on
                    

                    Nothing else comes even half as close in terms of utility.

                    1. 4

                      I use https://github.com/ellie/atuin to keep a syncable sqlite database of my shell history. Hit Ctrl+R and go through an interactive search. It’s pretty great.

                      1. 2

                        aww yay, glad to hear you like it! :D

                        1. 1

                          This is really useful thanks for sharing

                      2. 6

                        k for kubectl

                        1. 3

                          I make k a function which inspects the args and splices in $KUBE_CONTEXT and $KUBE_NAMESPACE in appropriate places, so that I can use .envrc and direnv(1) to work in the appropriate kubernetes context and namespace for a given app.

                          1. 2

                            God yes. When people see I have that they chuckle, and then after maybe 10 minutes of working in k8s with them, they immediately make the alias too.

                          2. 6

                            The one that probably gets the most use is

                            alias _="cd $(mktemp -d) ; "
                            

                            It creates and drops you into a /tmp dir. These get automatically cleaned up on reboot. The sets directory at setting of the alias. It will always take you back to the same tmp dir for that shell session. Its pretty basic but prevents a lot of cutter.

                            1. 2

                              I learned that /tmp is not always mounted as tmpfs; on WSL, for instance, this directory persists even after reboot.

                              To ensure mktemp -d creates an actual temporary directory, one should create and mount a tmpfs themselves (in their home directory, maybe?), and have a $TMPDIR environment variable pointing to this directory, before calling mktemp(1). Seems inefficient, though.

                            2. 5

                              Opening JIRA tickets at work (replace DEV with your prefix):

                              (simple? yes. Took me forever to consider even doing? yes. HUGE timesaver in meetings where people just rattle off ticket numbers? god yes.)

                              function jira() {
                                open https://<our_domain>.atlassian.net/browse/DEV-${1}
                              }
                              

                              Up command (copied from stackoverflow) – Takes optional number of levels to cd ../:

                              function up() {
                                local d=""
                                limit=$1
                                for ((i=1 ; i <= limit ; i++))
                                  do
                                    d=$d/..
                                  done
                                d=$(echo $d | sed 's/^\///')
                                if [ -z "$d" ]; then
                                  d=..
                                fi
                                cd $d
                              }
                              
                              1. 1

                                Have done similar thing, will attest to its utility.

                                1. 1

                                  Doing this with DNS search domains company-wide is also a good idea: typing http://jira/1234 should redirect you to the correct ticket.

                                2. 3

                                  Aliases I always add:

                                  alias ..='cd ..'
                                  alias new='mkdir && cd'
                                  
                                  1. 3

                                    For vi addicts:

                                    alias :e=nvim
                                    alias :q=exit
                                    
                                    1. 1

                                      ah! I came to post the second one :)

                                    2. 3
                                      
                                      alias g="git"
                                      alias la='ls -lA --color=auto'
                                      alias sc='screen -xRS'
                                      alias sl='screen -list'
                                      
                                      # With this function you can explore the filsystem,
                                      # and display contents of both directories and files
                                      # without going to the beginning of the line to
                                      # switch between ls and less.
                                      l() {
                                          if [ -z "$2" -a -f "$1" ] ; then
                                              less "$1"
                                          else
                                              ls -l --color=auto "$@"
                                          fi
                                      }
                                      
                                      # Create and enter a directory
                                      function mkcd { mkdir -p "$1"; cd "$1"; }
                                      
                                      1. 2

                                        extra niceties with git

                                        ga -> git add

                                        gap -> git add -p

                                        gb -> git branch

                                        gc -> git checkout

                                        gp -> git push

                                        gbb -> git for-each-ref --sort=committerdate refs/heads/ --format=%(committerdate) %(refname:short)

                                        (last one prints your branches sorted by last commit date, great for finding the “recent branches”

                                        1. 1

                                          I have sl aliased to ls to catch typos lol

                                          1. 1

                                            If you install the sl package, you get a steam locomotive blocking your terminal for a few seconds.

                                          2. 1

                                            I happen to use basically the same l and mkcd functions. Tip: I would be tempted to put && between mkdir and cd.

                                            Here is an extended mkcd function that also allows to carry files while changing directory. I use fish, so it’s in fish:

                                            function mkcd --description 'create, move zero or more files into and enter directory'
                                                set -l argc (count $argv)
                                                if test $argc -eq 0
                                                    echo "Usage: $_ [carry files…] destdir/"
                                                    return
                                                end
                                                mkdir -p $argv[-1]
                                                and if test $argc -gt 1
                                                    mv $argv
                                                end
                                                and cd $argv[-1]
                                            end
                                            
                                          3. 3
                                            • I’ll use cpwd to copy the $PWD and then change to that directory in >= 1 tmux pane by pasting which works because I have autocd enabled.
                                            • I very frequently run git rimraf on the default branch to sync up and delete any local branches that were deleted from the origin.
                                            • I mimic zsh’s preexec & precmd helpers in bash to do things like update $DISPLAY to avoid stale values in tmux sessions, my history file, and run z to keep track of directory frecency.
                                            • My favorite shell function checks the weather.
                                            1. 2

                                              A PROMPT_COMMAND:

                                              • Puts the exit code in red at the start of the prompt if it’s non-zero.
                                              • Colours the hostname yellow if it’s reached via SSH.
                                              • Enables Git prompt if available.
                                              • Puts the prompt at the bottom of the terminal, where it belongs. :)
                                              • Re-reads history, so all terminals share history and none is lost to the terminal which happens to exit last.

                                              Most other things I want to remember are in my .bash_history.

                                              1. 2

                                                zsh only:

                                                alias -g PG="|grep"
                                                alias -g PL="|less"
                                                # foo PL instead of foo | less
                                                

                                                I use them daily since years

                                                pvrun: run any command, but mostly cp/mv/tar, wrapped by pv to view I/O progress

                                                Not exactly shell but still use them daily, in my .tigrc:

                                                # u to fixup selected commit
                                                bind main u !git commit --fixup=%(commit)
                                                # r to rebase to selected commit
                                                bind main r !git rebase -i %(commit)~
                                                # P to push-create a new branch pointing at selected commit
                                                bind main P !sh -c "git push origin %(commit):refs/heads/$(printf 'branch name? ' >&2; read reply; echo $reply) --force"
                                                
                                                1. 2

                                                  c for cargo and then a bunch of aliases for subcommands in ~/.cargo/config (x = "clean" and so on)

                                                  One git alias that I use quite a lot is cane = commit --amend --no-edit. Then pi = !git push ionut +$(git rev-parse --abbrev-ref HEAD) to push (amended) commits for my current branch (ionut is the remote for my upstream fork).

                                                  1. 2

                                                    It is not an alias, but my zsh config does this really nice thing where “if a shell command completes when the terminal is not the foreground window, it sends me an alert that I can click to bring that terminal to the foreground”: https://codearcana.com/posts/2013/06/11/my-zsh-theme.html

                                                    https://github.com/awreece/prezto/blob/76c70b21d8f6d1f3e5f731fa4040e1a2ff49b702/modules/notify/functions/notify_last_command#L25

                                                      callback="osascript -e 'tell application \"Terminal\"' \
                                                                          -e 'activate' \
                                                                          -e 'set index of window id $terminal_window_id to 1' \
                                                                          -e 'end tell'"
                                                    

                                                    It also does a lot of the other nice things, e.g. coloring prompt based on success/failure and showing execution time of last run command.

                                                    1. 2

                                                      An alias I use often is mcd which just does mkdir && cd something. I have it since my DOS days I think.

                                                      1. 2

                                                        I’m kind of surprised this hasn’t been mentioned yet, it’s bee around for some time and certainly is one of the most useful features in my .scrc

                                                        # ARCHIVE EXTRACTION
                                                        # usage: ex <file>
                                                        ex () {
                                                          if [ -f $1 ] ; then
                                                            case $1 in
                                                              *.tar.bz2)    tar xjf $1    ;;
                                                              *.tar.gz)     tar xzf $1    ;;
                                                              *.tar.xz)     tar xf $1     ;;
                                                              *.tar)        tar xf $1     ;;
                                                              *.tar.zst)    uzstd $1      ;;
                                                              *.bz2)        bunzip2 $1    ;;
                                                              *.rar)        unrar x $1    ;;
                                                              *.gz)         gunzip $1     ;;
                                                              *.tbz2)       tar xjf $1    ;;
                                                              *.tgz)        tar xzf $1    ;;
                                                              *.zip)        unzip $1      ;;
                                                              *.Z)          uncompress $1 ;;
                                                              *.7z)         7z x $1       ;;
                                                              *.deb)        ar x $1       ;;
                                                              *)    echo "'$1' cannot be extracted via ex()" ;;
                                                            esac
                                                          else
                                                            echo "'$1' is not a valid file"
                                                          fi
                                                        }
                                                        

                                                        Another little one I often use which is useful if you are making edits to files and keeping backups of originals:

                                                        # swap 2 filenames around, if they exist
                                                        # usage: swap <file1> <file2>
                                                        swap () {
                                                            local TMPFILE=tmp.$$
                                                            mv "$1" $TMPFILE
                                                            mv "$2" "$1"
                                                            mv $TMPFILE "$2"
                                                        }
                                                        
                                                        1. 2
                                                          alias rg="rg -A=3 -B=3"
                                                          

                                                          When I use rg to search a codebase, this gives me three lines of context before and after each match. I don’t keep a ripgrep config file; this is all I need. It’s a great default.

                                                          I can always override this by setting -A or -B again in a command:

                                                          rg -A=10 my-search-term
                                                          
                                                          1. 1

                                                            Couldn’t you do rg-C 5?

                                                            1. 4

                                                              Setting -A and -B explicitly allows for changing them independently on-the-fly. Passing -A or -B after passing -C resets the opposite-direction context to zero.

                                                              1. 2

                                                                Yeah, I could. Good suggestion.

                                                            2. 2
                                                              alias reload="source ~/.zshrc"
                                                              alias zshrc="vi ~/.zshrc; reload"
                                                              

                                                              (replace vi with whatever you want)

                                                              1. 1

                                                                Hah! I did similar with vizsh and srczsh (and accompanying vizshe/srczshe for the .zshenv file)

                                                              2. 2

                                                                Related, I use this snippet every now and again to see what commands I am using a lot to see if I can generate aliases for them.

                                                                history | cut -f 7- -d " " | sort | uniq -c | sort | tail -20

                                                                1. 1

                                                                  I have an alias to search the shell’s command history using fzf (on ksh) then copy it to the clipboard

                                                                  alias h='fc -l -n -r 1 | nuniq | sed -Ee "s/^[[:blank:]]+//" | fzf | xclip -selection c'
                                                                  
                                                                2. 2

                                                                  git-commit-co-author prompts you to choose a co-author (using fzf) and then runs git commit with Co-authored-by: <coauthor> at the end (see GitHub docs):

                                                                        # Thanks https://github.com/hpcsc/dotfiles/blob/63f194aa553ef83f9edec76991f2265f7962b00e/link/common/zsh/.functions/fzf-functions/fcm
                                                                        function git-commit-co-author() {
                                                                          SELECTED_AUTHORS=$(git shortlog -sne | awk '{$1=""}1' | fzf -m)
                                                                          MESSAGE="\n\n"
                                                                          # convert newline-delimited string to array, zsh way: https://stackoverflow.com/a/2930519
                                                                          AUTHORS=("''${(f)SELECTED_AUTHORS}")
                                                                          for AUTHOR in $AUTHORS[@]; do
                                                                            MESSAGE="''${MESSAGE}Co-authored-by: ''${AUTHOR}\n"
                                                                          done
                                                                          if [[ "$1" == "-m" ]]; then
                                                                            git commit -m "$2$(echo -e ''${MESSAGE})"
                                                                          else 
                                                                            git commit $@ -t <(echo -e ''${MESSAGE})
                                                                          fi
                                                                        }
                                                                  

                                                                  I have aliased it to gcap and run it regularly when pair-programming. It’s not perfect, there are some unhandled edge cases but it works perfectly for me.

                                                                  1. 2
                                                                    1. 1

                                                                      Not super interesting I reckon. But the ones I use the most.

                                                                      ..='cd ..'
                                                                      ip='ip -br -c'
                                                                      home='git --work-tree=/home/fox --git-dir=/home/fox/.config/home.git'
                                                                      
                                                                      i3conf='vim ~/.config/i3/config'
                                                                      zshrc='vim ~/.config/zsh/.zshrc && source ~/.config/zsh/.zshrc'|
                                                                      

                                                                      I don’t really have a lot of super useful aliases. Most of the time is spent making git config aliases and vim stuff.

                                                                      1. 1

                                                                        Is that BSD or a mac? My ip doesn’t know either flag.

                                                                        1. 2

                                                                          That is iproute2. The goal is to have ip be brief by default because I simply do not care about all the information.

                                                                          λ ~ » /usr/bin/ip a
                                                                          1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
                                                                              link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
                                                                              inet 127.0.0.1/8 scope host lo
                                                                                 valid_lft forever preferred_lft forever
                                                                              inet6 ::1/128 scope host
                                                                                 valid_lft forever preferred_lft forever
                                                                          2: wlp0s20f3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
                                                                              link/ether 10:3d:1c:e9:f5:cf brd ff:ff:ff:ff:ff:ff
                                                                              inet 192.168.1.11/24 brd 192.168.1.255 scope global dynamic noprefixroute wlp0s20f3
                                                                                 valid_lft 78751sec preferred_lft 78751sec
                                                                              inet6 fe80::9f2c:5a98:d8ef:b06e/64 scope link noprefixroute
                                                                                 valid_lft forever preferred_lft forever
                                                                          3: enp0s31f6: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
                                                                              link/ether 90:2e:16:5e:1a:b5 brd ff:ff:ff:ff:ff:ff
                                                                          14: enp36s0u1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
                                                                              link/ether 00:50:b6:9f:fe:25 brd ff:ff:ff:ff:ff:ff
                                                                          
                                                                          λ ~ » ip a
                                                                          lo               UNKNOWN        127.0.0.1/8 ::1/128
                                                                          wlp0s20f3        UP             192.168.1.11/24 fe80::9f2c:5a98:d8ef:b06e/64
                                                                          enp0s31f6        DOWN
                                                                          enp36s0u1        DOWN
                                                                          
                                                                          1. 1

                                                                            Thanks, but that’s why I was asking:

                                                                            ii  iproute2                              5.5.0-1ubuntu1
                                                                            

                                                                            ip -br doesn’t work and neither does ip -c or ip -br -c.

                                                                            And now I finally grasped that it would output the same as 'ip' - so it is -brief -color. Sorry, brainfart (ofc I searched before I asked that last question..) :P

                                                                            Apparently I have never used either flag and didn’t notice them in the manual. – signed, someone gowing up with ifconfig

                                                                            1. 1

                                                                              Yeah I found the documentation for these commands a bit lacking when I started utilizing them initially.

                                                                        2. 1

                                                                          ..='cd ..'

                                                                          I was going to post this as my most useful, because I just it all the time.

                                                                          I also have ...="cd ../.." and so on for going up more levels. Probably not useful beyond four or five levels due to how quickly can you count how deep you are in the CWD.

                                                                          Edit: Just to be clear, I’m talking about me visually counting up how many levels deep I am in the directory tree. Beyond three or four, I tend to just go up that much, and then look and see where I am and maybe do it again, with my finger hovering over the ‘.’ key. I don’t have a problem rapidly tapping out the ‘.’ nine times to go up 8 levels, the difficulty (for me) is determining that I want to go up 8, vs. 7 or 9 levels.

                                                                          1. 1

                                                                            Don’t want to keep posting it so I’ll link to the reply i made to the parent:

                                                                            https://lobste.rs/s/qgqssl/what_are_most_useful_aliases_your_bashrc#c_fqu7jd

                                                                            You might like to use it too!

                                                                          2. 1

                                                                            You (and others) might be interested in the one from my post to this:

                                                                            function up() {
                                                                              local d=""
                                                                              limit=$1
                                                                              for ((i=1 ; i <= limit ; i++))
                                                                                do
                                                                                  d=$d/..
                                                                                done
                                                                              d=$(echo $d | sed 's/^\///')
                                                                              if [ -z "$d" ]; then
                                                                                d=..
                                                                              fi
                                                                              cd $d
                                                                            }
                                                                            

                                                                            Allows you to just do up 4 to get cd ../../../..

                                                                            LIFE-saver.

                                                                            1. 2

                                                                              Even more fun (only works in zsh, as far as I know):

                                                                              function rationalize-dot {
                                                                                  if [[ $LBUFFER = *... ]]; then
                                                                                      LBUFFER=${LBUFFER[1,-2]}
                                                                                      LBUFFER+=/..
                                                                                  else
                                                                                      LBUFFER+=.
                                                                                  fi
                                                                               }
                                                                               zle -N rationalize-dot
                                                                               bindkey . rationalize-dot
                                                                              

                                                                              You can make this even better by adding setopt auto_cd to your config, so that if you type a directory path zsh automatically changes to that directory.

                                                                              1. 1

                                                                                I tend to use https://github.com/wting/autojump for smart CDing, personally!

                                                                              2. 2
                                                                                alias .="cd .."
                                                                                alias ..="cd ../.."
                                                                                alias ...="cd ../../.."
                                                                                alias ....="cd ../../../.."
                                                                                
                                                                                1. 1

                                                                                  Interesting. I’ve never tried to install / use those “smart” cd replacements, where you can type “cd foobar” and it looks at your recent working directories to find a “foobar” and go there.

                                                                                  I was thinking about a variant of your up function that does something like that, where I can type “up foo” in the current directory:

                                                                                  /home/username/foobar/one/two/three/four/
                                                                                  

                                                                                  And so it just looks into successive parent directories for anything matching “foo”, and the first one it finds is the destination.

                                                                                  1. 2

                                                                                    oh man – just use Autojump https://github.com/wting/autojump. I use it on every machine i own and it’s a GODSEND.

                                                                                    1. 1

                                                                                      That was what I was talking about. I’ll have to give it or maybe zoxide a try and see if I stick with it.

                                                                              3. 1

                                                                                .. for cd ..
                                                                                sl for ls
                                                                                gittree for "git log --graph --all --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)'" for displaying a nice git history tree.

                                                                                1. 1

                                                                                  Magic on top of Fuzzy Finder:

                                                                                  # bind ctrl-E to "edit fuzzy"
                                                                                  function edit_fuzzy() {
                                                                                    TARGET=$(fzf)
                                                                                    if [ $? -eq 0 ]
                                                                                    then
                                                                                      echo -e "${PS1@P}edit $TARGET"
                                                                                      history -s "edit $TARGET"
                                                                                      edit "$TARGET"
                                                                                      READLINE_LINE=""
                                                                                    fi
                                                                                  }
                                                                                  
                                                                                  bind -x '"\C-e":edit_fuzzy'
                                                                                  

                                                                                  Which binds ctrl-E to “select a file, then open it in ‘edit’” (an alias for kwrite). Adjust editor name for taste. The magic is that this also pretends that you typed in “edit filename” manually and pressed return, going so far as to inject that command into your history.

                                                                                  1. 1

                                                                                    The best answer “for you” here is probably a meta answer. Save all (or a very large portion) of your shell history - not suppressing duplicates - and periodically examine it for useful abstractions/abbreviations.

                                                                                    This can probably be automated, and I’d look for child responses to this post for someone mentioning such tools, but it’s also kind of hard AI-complete to extract good abstractions statistically (and indeed, somewhat subjective in the end, even with personalized statistics). So, while a simple histogram of exact strings is easy and might get you started, the best you can hope for still leaves a lot of manual work (such as separating out the alias/function/script from arguments/context). It is still more precise to your own workflows than trying to crowd source answers here.

                                                                                    The crowd sourcing might get you lots of other nice shell magic ideas, though. :-)

                                                                                    All that said, I can re-re-recommend showing exit statuses in prompts which I have been doing in Zsh since 1994, re-recommend a “cd ../..” hierarchy (I use one ‘.’ for parent, two for parent-of-parent where the one ‘.’ needs to be a shell function that does a ‘source’ only if it has an argument to source else the cd; Autocd makes “..” by itself largely unneeded), re-recommend what Zsh calls REPORTTIME re-done in Bash elsethread, and add a family of head-tail wrappers that use $LINES (updated upon SIGWINCH by Bash/Zsh) to have tq for “tail quarter”, th for “tail half” and so on using $((LINES/4)) and $((LINES/2)). While there are many more, I’d say these 4 categories might have wide appeal (2 of which are not even aliases/functions/wrappers!)

                                                                                    1. 1

                                                                                      There aren’t a lot of game changers, but this alternative to ps aux | grep is what I use all the time:

                                                                                      function px() {
                                                                                          local arg=$1
                                                                                          local len=${#arg}
                                                                                          local x=${arg:0:1}
                                                                                          local xs=${arg:1:$len}
                                                                                          /bin/ps aux | grep "[${x}]${xs}"
                                                                                      }
                                                                                      

                                                                                      colorize is also quite handy:

                                                                                      function colorize {
                                                                                        if [ -z "$2" ]; then
                                                                                          grep --color=always "$1\|^"
                                                                                        else
                                                                                          grep --color=always "$1\|^" $2
                                                                                        fi
                                                                                      }
                                                                                      

                                                                                      I have them all on github, although they should be documented: https://github.com/winks/dotfiles/blob/master/zsh/functions.zsh

                                                                                      1. 1

                                                                                        I use these three a lot.

                                                                                        alias realias='$EDITOR ~/.bash_aliases && source ~/.bash_aliases'
                                                                                        alias refunction='$EDITOR ~/.bash_functions && source ~/.bash_functions'
                                                                                        mkcd() {
                                                                                        	mkdir -p "$1" && cd "$1"
                                                                                        }
                                                                                        

                                                                                        But my real favorite is the following. I’m a teacher, and I frequently have to switch from $HOME/Documents/git-repos/schoolname/YYYY/classname-section1/grades to $HOME/Documents/git-repos/schoolname/YYYY/classname-section2/grades. With this function, I enter ccd 1 2 and I’m where I need to be. (That FIXME has been there forever. I make mistakes rarely enough that I haven’t bothered to fix it.)

                                                                                        ccd() {
                                                                                            case "$#" in
                                                                                                0|1)
                                                                                                    builtin cd $1
                                                                                                    ;;
                                                                                                2)
                                                                                                    newdir=${PWD//$1/$2}
                                                                                                    # FIXME TODO
                                                                                                    # If the user enters two wrong variables, they trigger the first
                                                                                                    # branch of this case statement. They should trigger a different
                                                                                                    # error message.
                                                                                                    case "$newdir" in
                                                                                                        $PWD)
                                                                                                            printf "ccd: \$PWD is already $PWD\n" >&2
                                                                                                            return 1
                                                                                                            ;;
                                                                                                        *)
                                                                                                            builtin cd "$newdir"
                                                                                                            pwd
                                                                                                            ;;
                                                                                                    esac
                                                                                                    ;;
                                                                                                *)
                                                                                                    printf "ccd: wrong arg count\n" 1>&2
                                                                                                    return 1
                                                                                                    ;;
                                                                                            esac
                                                                                        }
                                                                                        
                                                                                        1. 1

                                                                                          I have several hundreds. Some I use all the time:

                                                                                          md () {
                                                                                                  mkdir -p $1
                                                                                                  cd $1
                                                                                          }
                                                                                          
                                                                                          mvd () {
                                                                                                  mkdir -p ${@[$#]}
                                                                                                  mv $*
                                                                                                  cd ${@[$#]}
                                                                                          }
                                                                                          
                                                                                          cpd () {
                                                                                                  mkdir -p ${@[$#]}
                                                                                                  cp -r $*
                                                                                                  cd ${@[$#]}
                                                                                          }
                                                                                          
                                                                                          ec: aliased to emacsclient -t
                                                                                          
                                                                                          trz: aliased to rsync -trz
                                                                                          
                                                                                          1. 1

                                                                                            I wish I had time to participate more in the thread, but my entire system setup is in my repo: https://github.com/kbd/setup

                                                                                            Here’s my bin dir: https://github.com/kbd/setup/tree/master/HOME/bin

                                                                                            My aliases: https://github.com/kbd/setup/blob/master/HOME/bin/shell/aliases.sh

                                                                                            Worth noting things like ‘autopager’, ‘fzr’, ‘t’ (touch, but creates intermediate directories), ‘mcd’, ‘install-manual’, ‘kw’ (opens any program in a new split in kitty, used constantly). Also see my extensive git aliases that make heavy use of fzf. A lot of people are mentioning prompts… I wrote my own in Zig so it’s fast and cross-shell, see kbd/prompt.

                                                                                            1. 1

                                                                                              alias gitdo='gitdiff ...@{u}'

                                                                                              Paired with git fetch origin, you see the diff of what changes other people made to the remote copy of the branch, but not polluted with any differences you locally have committed to the branch. i.e. strictly their work, none of your work.

                                                                                              1. 1

                                                                                                These will only work in zsh but I have a few for iterating over input which are useful in a pipeline:

                                                                                                alias 'each{'='while { read -rA argv } {'
                                                                                                alias 'each'='while { read -rA argv }'
                                                                                                alias 'eachl{'='while { read -r argv } {'
                                                                                                alias 'eachl'='while { read -r argv }'
                                                                                                

                                                                                                Another alias where I include the opening brace is this one for enabling xtrace:

                                                                                                alias -- '-x{'='() { setopt localoptions xtrace; '
                                                                                                

                                                                                                I also have a few aliases with names starting with +, e.g. for adding the current directory to the path or fpath arrays:

                                                                                                alias -- +fpath='fpath=( ~+ $fpath)'
                                                                                                alias -- +path='path=( ~+ $path)'
                                                                                                

                                                                                                For modifying arrays, it is also useful to alias vared with IFS changed to do line-based editing:

                                                                                                alias lvared="IFS=\$'\n\n' vared"
                                                                                                

                                                                                                And if you use vi mode, you may prefer:

                                                                                                alias vared='vared -i vi-cmd-mode'
                                                                                                

                                                                                                Aliases are also useful for applying noglob and nocorrect for a few commands. git mostly does its own globbing so there’s little need for zsh globbing with it and this avoids a certain amount of quoting. nocorrect is useful with commands like mkdir that take something which won’t exist yet as an argument.

                                                                                                for com in alias expr find git iptables mattrib mcopy mdir mdel unset which;
                                                                                                    alias $com="noglob $com"
                                                                                                

                                                                                                A zsh odditity is that if an alias ends in a space, it will do alias expansions on the next word too. So this can be applied for commands that precede other commands:

                                                                                                for com in command builtin time nice - nocorrect exec rusage noglob eval nohup;
                                                                                                    alias -- $com="$com "
                                                                                                

                                                                                                Aside from that, most of my aliases are fairly boring and would work in bash. Here’s just a few of them:

                                                                                                alias apb=ansible-playbook
                                                                                                alias iperl='perl -de1'
                                                                                                alias peminfo='openssl x509 -text -in'
                                                                                                alias toimg='convert -font Inconsolata-Regular label:@-'
                                                                                                alias scat='sed -n l'
                                                                                                alias serve='ruby -run -ehttpd . -p8000'
                                                                                                alias smarties='smartctl -A -f brief'
                                                                                                alias week='date +%V'
                                                                                                alias xkev="xev|sed -ne '/^KeyPress/,/^$/p'"
                                                                                                

                                                                                                I have quite a few wrapping curl for sites like wttr.in, rate.sx, ifconfig.me and sprunge.us.

                                                                                                1. 1

                                                                                                  Classics: l=ls; c=cd; s=cd ..

                                                                                                  Typos: sl=ls; f=fg; fgfg=fg; gf=fg

                                                                                                  p=python3; cr=cargo run. Various important folders have their names aliased to cd into them.

                                                                                                  +=git add. g is an alias to gt, a python script that does more alias expansion. g c=git commit; g am=git commit --amend; g dc=git diff --cached. It also prints a warning if I commit certain monstrosities. But lately I try to favor fugitive.

                                                                                                  i3: keybindings for a script to wget/yt-dlp the url in the clipboard, showing a menu for: into a particular directory, with a particular name, using the previous_name+1.

                                                                                                  1. 1
                                                                                                    alias rm="rm -i"
                                                                                                    

                                                                                                    Prompt when rm-ing

                                                                                                    alias cdtemp="cd \$(mktemp -d)"
                                                                                                    

                                                                                                    Create a temporary directory an cd into it, very useful when experimenting on a clean slate

                                                                                                    alias pb="curl -F\"file=@-;\" https://envs.sh"
                                                                                                    

                                                                                                    Simple paste bin, I can use it on a regular file

                                                                                                    pb file
                                                                                                    

                                                                                                    or pipe into it

                                                                                                    cat file | pb
                                                                                                    

                                                                                                    Color my diffs

                                                                                                    alias diff="colordiff"
                                                                                                    

                                                                                                    Also

                                                                                                    fpwd() {
                                                                                                    pwd | sed -e "s|^$HOME|~|" -e 's-\([^/.]\)[^/]*/-\1/-g'
                                                                                                    }
                                                                                                    

                                                                                                    ouputs a fish style pwd ~/s/mkws.sh, I use it in my PS1.

                                                                                                    I have a ~/bin/precommit script that uses my linters https://adi.onl/linters.html. I use it as a generic linter.

                                                                                                    #!/bin/sh
                                                                                                    
                                                                                                    for f in *
                                                                                                    do
                                                                                                    t=$(file -bi "$f")
                                                                                                    test ${t#text} == $t && continue
                                                                                                    lis "$f"
                                                                                                    lts "$f"
                                                                                                    lml "$f"
                                                                                                    lfn "$f"
                                                                                                    ltn "$f"
                                                                                                    done
                                                                                                    

                                                                                                    I store my system wide configs in $HOME in a mirror directory structure of the / directory:

                                                                                                    /home/adi
                                                                                                      etc
                                                                                                         httpd.conf
                                                                                                         doas.conf
                                                                                                         hosts
                                                                                                      var
                                                                                                        cron
                                                                                                    

                                                                                                    I use

                                                                                                    crontab() {
                                                                                                    if test "$#" -eq 1 &&
                                                                                                    test "$1" == "-e"
                                                                                                    then
                                                                                                    "$VISUAL" "$LOCALCRONTAB"
                                                                                                    command crontab "$LOCALCRONTAB"
                                                                                                    else
                                                                                                    command crontab "$@"
                                                                                                    fi
                                                                                                    }
                                                                                                    

                                                                                                    To actually edit my /var/cron/tabs/adi file and install it system wide transparently.

                                                                                                    My dotfiles https://adi.onl/.*.html.

                                                                                                    1. 1

                                                                                                      alias rm=“rm -i”

                                                                                                      Prompt when rm-ing

                                                                                                      This can be quite a dangerous thing to do. It was really popular where I used to work and I know of more than one instance where someone was so used to it being there that they accidentally removed a load of files when using a different login. If you want such an alias call it something else like ri.

                                                                                                      1. 1

                                                                                                        Thanks for the warning! Not a bad idea!

                                                                                                    2. 1

                                                                                                      Some zshzle(1) and zshmisc(1) goodness.

                                                                                                      # Submit command but keep command & cursor at same position
                                                                                                      bindkey '^\n' accept-and-hold
                                                                                                      
                                                                                                      stty -ixon # Disable XON/XOFF output control (^S/^Q)
                                                                                                      bindkey '^R' history-incremental-pattern-search-backward
                                                                                                      bindkey '^S' history-incremental-pattern-search-forward
                                                                                                      
                                                                                                      # No longer need to quote URLs with yt-dlp (youtube-dl)
                                                                                                      alias ytdl='noglob yt-dlp'
                                                                                                      
                                                                                                      1. 1

                                                                                                        cdg => cd up the filesystem until you find the directory that contains a .git dir.

                                                                                                        This one’s actually an eshell function:

                                                                                                        (defun eshell/cdg ()
                                                                                                          "Change directory to the project's root."
                                                                                                          (eshell/cd (locate-dominating-file default-directory ".git")))
                                                                                                        
                                                                                                        1. 3

                                                                                                          or in pure shell: cd "$(git rev-parse --show-toplevel)"

                                                                                                        2. 1

                                                                                                          I have a fzf setup in fish that started out as a function, and then moved into a plugin: https://github.com/mk12/fish-fzf. It mostly works with a single shortcut that aims to “do what I mean”.

                                                                                                          • Ctrl-O: fzf files
                                                                                                            • Already started typing a path? Start from there.
                                                                                                            • Extra stuff at end of that path? Start with that query.
                                                                                                            • Has keybindings to switch files/directories, navigate up/down directories, show hidden files, etc.
                                                                                                            • Previews files with bat and directories with exa, or falls back to cat and ls.
                                                                                                          • After selection:
                                                                                                            • Command line not empty, or more than 1 selected? Insert on command line.
                                                                                                            • Selected 1 file? Open with $EDITOR.
                                                                                                            • Selected 1 directory? cd to it.
                                                                                                          1. 1

                                                                                                            alias cls="clear && ls" is the first thing I set up in any new environment.

                                                                                                            1. 1

                                                                                                              vi mapped to vim :)

                                                                                                              1. 1

                                                                                                                Mine have to be these:

                                                                                                                alias ..="cd .."
                                                                                                                
                                                                                                                alias t="tmux new -s "
                                                                                                                alias ta="tmux a -t "
                                                                                                                alias tl="tmux ls"
                                                                                                                
                                                                                                                1. 4

                                                                                                                  My very first alias was same as your first one here.. I just made a few more also

                                                                                                                  alias ...="cd ../.."
                                                                                                                  

                                                                                                                  Up to four or five dots (sorry, on a phone here, it’s a pain to type it out). Works really well.

                                                                                                                  Whenever I set up a new laptop it’s always the first thing I add

                                                                                                                2. 1

                                                                                                                  I like fixssh:

                                                                                                                  fixssh () {
                                                                                                                          for key in SSH_AUTH_SOCK SSH_CONNECTION SSH_CLIENT
                                                                                                                          do
                                                                                                                                  if (
                                                                                                                                                  tmux show-environment | grep --color=auto "^${key}" > /dev/null
                                                                                                                                          )
                                                                                                                                  then
                                                                                                                                          value=`tmux show-environment | grep "^${key}" | sed -e "s/^[A-Z_]*=//"`
                                                                                                                                          export ${key}="${value}"
                                                                                                                                  fi
                                                                                                                          done
                                                                                                                  }
                                                                                                                  
                                                                                                                  1. 1

                                                                                                                    Bash has $SRANDOM for a 32-bit cryptographically secure random number. ZSH however doesn’t. So I wrote a simple function:

                                                                                                                    srandom() {
                                                                                                                    	zmodload zsh/system
                                                                                                                    	local byte
                                                                                                                    	local -i rnd=0 
                                                                                                                    	repeat 4; do
                                                                                                                    		sysread -s 1 byte < /dev/urandom || return
                                                                                                                    		rnd=$(( rnd << 8 | #byte )) 
                                                                                                                    	done
                                                                                                                    	print -r -- $rnd
                                                                                                                    }
                                                                                                                    

                                                                                                                    In action:

                                                                                                                    % srandom
                                                                                                                    756370670