[ home ]

Bash function: interactively pick from directory history

I use these about 100x a day. Productivity booster!

cd: wrapper around Bash builtin, updating dir history.

hcd: pick a recently visited directory from history list using dialog.

shcd (simplify/strip history list): remove intermediate dirs (e.g. remove "/foo" when "/foo/bar" is also present), and remove non-existent dirs.


    CDHIST=~/.dir_history

    function cd() {

        d="$1"

        # Try to change to given dir first - exit if not possible. Continue with resolved CWD.

        if [ -n "$d" ]; then builtin cd "$d"; else builtin cd; fi
        [ $? -ne 0 ] && return

        d=$( pwd )

        # Filter out dirnames that we don't want in our history list.

        [ "$d" = "/"     ] && return
        [ "$d" = "$HOME" ] && return

        # Delete any occurrences of dir in history list, 
        # and append dir to list (last line = most recent dir). 
        #
        # (Thus, re-visiting a dir already in the list 'refreshes' it.)
        #
        #   grep: -v: invert 
        #         -x: whole line match 
        #         -F: pattern is string 
        #         -e: force next arg to be pattern

        touch $CDHIST
        ( grep -v -x -F -e "$d" $CDHIST;  echo "$d" ) | tail > $CDHIST.tmp
        mv $CDHIST.tmp $CDHIST
    }

    function hcd() {

        [ -f $CDHIST ] || return

        local IFS=$'\n'

        local lst=()
        for a in $( tac $CDHIST ); do lst+=($a); lst+=(""); done

        dir=$( dialog  --keep-tite --menu  "choose dir"  0 0 0  "${lst[@]}"  2>&1  >/dev/tty )

        [ "$?" -ne 0 ] && return

        cd "$dir"  >/dev/null
    }

    function shcd() {

        [ -f $CDHIST ] || return

        local IFS=$'\n'

        local TMP=$CDHIST.tmp

        echo -n > $TMP

        for a in $( cat $CDHIST ); do

            if [ -d "$a" ]; then

                grep "$a/" $CDHIST >/dev/null

                if [ $? -ne 0 ]; then
                    echo "$a" >> $TMP
                fi
            fi
        done

        mv $TMP $CDHIST
    }