C shell pushd/popd on steroids as Korn Shell functions
Blogfinger inspires me to post some of my crazy KSH function code. The code below is a heavily hacked version of a similar functions that I got from Will several years ago. Someday I should post my partial ASN.1 DER encoder/decoder written in KSH :)
Syntax highlighting courtesy of VIM and its :TOhtml feature.
typeset|grep '^integer cdx$' > /dev/null || integer cdx=0 typeset|grep '^integer cdsx$' > /dev/null || integer cdsx=0 function cdhelp { cat <<-"EOF" Usage: cdinit [<file>] Usage: cdcl Initialize directory list and stack. Clear directory list and stack. Usage: cdfind <path> [quiet] Usage: cdgrep <partial path> [first] Find a directory, by exact match in the cd list. Find matching directories in the cd list. Usage: cdls Usage: cdrf [-a|--append] [<files>|-] Show the cd list. Use this to save your cd list. Read in a cd list and replace the current cd list. Usage: cdsv [<directory paths>] (if none given then CWD) Save the given or current directory to the cd list. Usage: cdow <index> Overwrite the given entry in the cd list with the CWD. Usage: cdto <index>|<path>|[+]<partial path> Change the current directory to an entry from the cd list, or, if a path is given, then change to the given path and save to the cd list. Usage: cdrm [<path>|<index>] Remove a directory, or the current directory from the cdlist. Usage: cdsort Sort the cd list (alphanumerically) Usage: pushd [<directory>] Usage: popd [<number>] Usage: rightd [<number>] (reverse of popd) Usage: dirs (shows dirs in pushd/popd stack) Directory stack, similar to the C-Shell built-ins of similar names. EOF } function cdfind { typeset p dir integer i if [[ $# -lt 1 || -z "$1" ]] then print "Usage: cdfind <path> [quiet]" return 5 fi i=0 p="$1" [[ "$1" != /* ]] && p="$PWD/$1" for dir in "${cdlist[@]}" do if [[ "$p" = "$dir" ]] then if [[ "$2" != quiet ]] then print "Found at index $i" return 0 fi return $i fi i=i+1 done return 255 } function cdgrep { typeset i s integer i=0 s=1 if [[ $# -lt 1 || $# -gt 2 || -z "$1" ]] then print "Usage: cdgrep <partial path> [first]" fi while [[ i -lt cdx ]] do if eval "[[ \"${cdlist[i]}\" = *${1}* ]]" then print "$i ${cdlist[i]}" s=0 [[ "$2" = first ]] && return 0 fi i=i+1 done return $s } function cdshow { typeset found_at cdfind "$PWD" quiet found_at=$? [[ $found_at -eq 255 ]] && found_at='[unsaved]' print "$found_at $PWD" return 0 } function cdto { typeset i j dir integer i if [[ $# -ne 1 || -z "$1" ]] then print "Usage: cdto <index>|<path>|[+]<partial path>" fi if [[ "$1" = +([0-9]) ]] then if cd "${cdlist[$1]}" then print "$1 ${cdlist[$1]}" return 0 fi else if [[ "$1" != \+* && -d "$1" ]] then if cd "$1" then cdsv > /dev/null cdshow return 0 fi fi cdgrep "${1#\+}" first|read j dir if [[ -d "$dir" ]] then if cd "$dir" then cdsv > /dev/null cdshow return 0 fi fi fi print "Could not cd to $1" return 1 } function cdls { integer i=0 while [[ i -lt cdx ]] do print $i ${cdlist[i]} i=i+1 done } cdcl () { cdx=0 cdsx=0 unset cdlist unset cdstack set -A cdlist set -A cdstack } function cdsv { typeset dir current integer i if [[ "$1" = -h || "$1" = --help ]] then print "Usage: cdsv [<directory paths>] (if none given then CWD)" return 1 fi # Look for $PWD in cdlist[] current="" if [[ $# -eq 0 ]] then current="current " set -- "$PWD" fi for dir in "$@" do cdfind "$dir" quiet i=$? if [[ $i -ne 255 ]] then print "The ${current}directory $dir is already in the cdlist ($i)" continue fi #cdlist[${#cdlist[@]}]="$PWD" cdlist[cdx]=$PWD cdx=cdx+1 done } # overwrite entry function cdow { integer i if [[ $# -ne 1 || "$1" != +([0-9]) ]]; then print "Usage: cdow index#(see cdls)" return 1 fi cdfind "$PWD" quiet i=$? if [[ "$1" -gt ${#cdlist[@]} ]] then print "Index is beyond cdlist end ($1 > ${#cdlist[@]})" return 1 fi if [[ $i -ne 255 ]] then print "The current directory is already in the cdlist ($i)" return 1 fi cdlist[$1]=$PWD return 0 } function cdrf { typeset f status dir spath typeset cdx_copy cdlist_copy usage integer cdx_copy=0 usage="Usage: cdrf [-a|--append] [<files>|-]" status=1 set -A cdlist_copy -- # Options while [[ $# -gt 0 && "$1" = -?* ]] do case "$1" in -s|--strip) spath=$2 shift ;; -a|--append) cdx_copy=$cdx set -A cdlist_copy -- "${cdlist[@]}" ;; *) print "$usage" return 1 ;; esac shift done # Default to reading stdin [[ $# -eq 0 ]] && set -- - # Process cdlist files for f in "$@" do if [[ "$f" = - ]] then # STDIN sed -e 's/^[0-9]* //' | while read dir do dir=${dir#$spath} [[ "$dir" != /* ]] && dir="$PWD/$dir" cdlist_copy[cdx_copy]=${dir} cdx_copy=cdx_copy+1 done status=0 continue fi # Find the cdlist file if [[ ! -f "$f" && ! -f "$HOME/.cdpath.$f" ]] then print "No such cdpath file $p or $HOME/.cdpath.$f" continue fi [[ ! -f "$f" && -f "$HOME/.cdpath.$f" ]] && f="$HOME/.cdpath.$f" # Read the cdlist file sed -e 's/^[0-9]* //' "$f" | while read dir do dir=${dir#$spath} [[ "$dir" != /* ]] && dir="$PWD/$dir" cdlist_copy[cdx_copy]=${dir} cdx_copy=cdx_copy+1 done status=0 done [[ $status -ne 0 ]] && return $status # Install new cdlist cdcl cdx=$cdx_copy set -A cdlist -- "${cdlist_copy[@]}" return 0 } function cdsort { cdls | sed -e 's/^[0-9]* //' | sort -u | cdrf - cdls } function cdrm { integer i if [[ -n "$1" && "$1" != +([0-9]) ]] then cdfind "${1:-$PWD}" quiet i=$? elif [[ -n "$1" && "$1" = +([0-9]) ]] then i=$1 elif [[ $# -ne 0 ]] then print "Usage: cdrm <path>|<index>" return 1 else cdfind "${1:-$PWD}" quiet i=$? fi if [[ "$i" -eq 255 ]] && return 1 then cdfind "${1:-$PWD}" fi cdls|grep -v "^${i} "|sed -e 's/^[0-9]* //'|cdrf i=$? cdls return $i } function pushd { if [[ $# -gt 0 && ! -d "$1" ]] then print "Can't cd to: $1" return 1 fi cdstack[$cdsx]="$PWD" if cd "${1:-.}" then cdsx=cdsx+1 cdstack[cdsx]="$PWD" [[ "$2" = sv || "$2" = save ]] && cdsv cdshow else print "Could not cd to $1" return 1 fi return 0 } function pushdsv { pushd "$1" save } function popd { if [[ $((cdsx-${1:-1})) -lt 0 || $((${#cdstack[@]} - ${1:-1})) -lt 0 ]] then print "Empty stack or popping too much" return 1 fi if [[ ! -d "${cdstack[cdsx-${1:-1}]}" ]] then print "Can't cd to: ${cdstack[cdsx-${1:-1}]}" return 2 fi if cd "${cdstack[cdsx-1]}" then cdsx=cdsx-1 cdshow else print "Could not popd to ${cdstack[cdsx-1]}" return 1 fi return 0 } function dirs { integer i if [[ ${#cdstack[@]} -eq 0 ]] then print "Empty stack" return 1 fi i=1 print -n "${cdstack[0]}" while [[ $i -le $((cdsx)) && $i -le ${#cdstack[@]} ]] do print -n " ${cdstack[i]}" i=i+1 done if [[ ${#cdstack[@]} -gt $cdsx && $i -lt ${#cdstack[@]} ]] then print -n " <-> " while [[ $i -lt ${#cdstack[@]} ]] do print -n " ${cdstack[i]}" i=i+1 done fi print return 1 } function rightd { typeset i integer i if [[ -n "$1" && "$1" != +([0-9]) ]] then print "Usage: rightd [<number>]" return 1 fi i=${1:-1} if [[ ${#cdstack[@]} -le $((cdsx+i)) ]] then print "No directories to the right on the stack" return 1 fi if [[ ! -d "${cdstack[cdsx+i]}" ]] then print "Can't cd to: ${cdstack[cdsx+i]}" return 2 fi if cd "${cdstack[cdsx+i]}" then cdsx=cdsx+i cdshow else print "Could not cd to ${cdstack[cdsx+i]}" return 1 fi return 0 } cdinit () { [[ -n "${recd}" ]] && return 0 cdcl if [[ $# -eq 0 && -f ~/lib/cdpaths ]] then cdrf < ~/lib/cdpaths elif [[ $# -eq 1 ]] then cdrf "$1" fi cdls } vicd () { ${EDITOR:-vi} ~/.kshcd } recd () { typeset recd recd=inprogress . ~/.kshcd recd="" } cdinit
Nicolas,
great stuff! Thanks!
It inspired me to a nice “mkdir && cd” function I wanted to have since ages, but never searched for or programmed – in my blog entry now.
cu,
Bernd
blogfinger said this on April 5, 2007 at 12:24 |