├── README └── z.sh /README: -------------------------------------------------------------------------------- 1 | z is the new j 2 | 3 | First, there was j: http://github.com/rupa/j/. 4 | 5 | Then, there was j2: http://github.com/rupa/j2/, with some python added. Made 6 | it easier to experiment with some stuff I'd been thinking about. 7 | 8 | Now there's this, where I rewrote j2 back in bash. I like it. Sorry about all 9 | the repos , but it kind of grew this way. 10 | 11 | The biggest change from j is the use of 'frecency' for weighting. Directories 12 | that have low ranking but were accesed recently, will quickly have higher rank. 13 | 14 | The -r switch preserves the old behavior. 15 | 16 | # maintains a jump-list of the directories you actually use 17 | # 18 | # INSTALL: 19 | # * put something like this in your .zshrc: 20 | # . /path/to/z.sh 21 | # function precmd () { 22 | # z --add "$(pwd -P)" 23 | # } 24 | # * cd around for a while to build up the db 25 | # * PROFIT!! 26 | # 27 | # USE: 28 | # * z foo # goes to most frecent dir matching foo 29 | # * z foo bar # goes to most frecent dir matching foo and bar 30 | # * z -r foo # goes to highest ranked dir matching foo 31 | # * z -t foo # goes to most recently accessed dir matching foo 32 | # * z -l foo # list all dirs matching foo (by frecency) 33 | -------------------------------------------------------------------------------- /z.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # maintains a jump-list of the directories you actually use 4 | # 5 | # INSTALL: 6 | # * put something like this in your .bashrc: 7 | # . /path/to/z.sh 8 | # * cd around for a while to build up the db 9 | # * PROFIT!! 10 | # 11 | # USE: 12 | # * z foo # goes to most frecent dir matching foo 13 | # * z foo bar # goes to most frecent dir matching foo and bar 14 | # * z -r foo # goes to highest ranked dir matching foo 15 | # * z -t foo # goes to most recently accessed dir matching foo 16 | # * z -l foo # list all dirs matching foo (by frecency) 17 | 18 | z() { 19 | local datafile=$HOME/.z 20 | if [ "$1" = "--add" ]; then 21 | # add 22 | shift 23 | # $HOME isn't worth matching 24 | [ "$*" = "$HOME" ] && return 25 | awk -v p="$*" -v t="$(date +%s)" -F"|" ' 26 | BEGIN { rank[p] = 1; time[p] = t } 27 | $2 >= 1 { 28 | if( $1 == p ) { 29 | rank[$1] = $2 + 1 30 | time[$1] = t 31 | } else { 32 | rank[$1] = $2 33 | time[$1] = $3 34 | } 35 | count += $2 36 | } 37 | END { 38 | if( count > 1000 ) { 39 | for( i in rank ) print i "|" 0.9*rank[i] "|" time[i] # aging 40 | } else for( i in rank ) print i "|" rank[i] "|" time[i] 41 | } 42 | ' $datafile 2>/dev/null > $datafile.tmp 43 | mv -f $datafile.tmp $datafile 44 | elif [ "$1" = "--complete" ]; then 45 | # tab completion 46 | awk -v q="$2" -F"|" ' 47 | BEGIN { split(substr(q,3),fnd," ") } 48 | { 49 | if( system("test -d \"" $1 "\"") ) next 50 | for( i in fnd ) $1 !~ fnd[i] && $1 = ""; if( $1 ) print $1 51 | } 52 | ' $datafile 2>/dev/null 53 | else 54 | # list/go 55 | while [ "$1" ]; do case "$1" in 56 | -h) echo "z [-h][-l][-r][-t] args" >&2; return;; 57 | -l) local list=1;; 58 | -r) local typ="rank";; 59 | -t) local typ="recent";; 60 | --) while [ "$1" ]; do shift; local fnd="$fnd $1";done;; 61 | *) local fnd="$fnd $1";; 62 | esac; local last=$1; shift; done 63 | [ "$fnd" ] || local list=1 64 | # if we hit enter on a completion just go there 65 | [ -d "$last" ] && cd "$last" && return 66 | [ -f "$datafile" ] || return 67 | local cd="$(awk -v t="$(date +%s)" -v list="$list" -v typ="$typ" -v q="$fnd" -v tmpfl="$datafile.tmp" -F"|" ' 68 | function frecent(rank, time) { 69 | dx = t-time 70 | if( dx < 3600 ) return rank*4 71 | if( dx < 86400 ) return rank*2 72 | if( dx < 604800 ) return rank/2 73 | return rank/4 74 | } 75 | function output(files, toopen, override) { 76 | if( list ) { 77 | if( typ == "recent" ) { 78 | cmd = "sort -nr >&2" 79 | } else cmd = "sort -n >&2" 80 | for( i in files ) if( files[i] ) printf "%-10s %s\n", files[i], i | cmd 81 | if( override ) printf "%-10s %s\n", "common:", override > "/dev/stderr" 82 | } else { 83 | if( override ) toopen = override 84 | print toopen 85 | } 86 | } 87 | function common(matches, fnd, nc) { 88 | for( i in matches ) { 89 | if( matches[i] && (!short || length(i) < length(short)) ) short = i 90 | } 91 | if( short == "/" ) return 92 | for( i in matches ) if( matches[i] && i !~ short ) x = 1 93 | if( x ) return 94 | if( nc ) { 95 | for( i in fnd ) if( tolower(short) !~ tolower(fnd[i]) ) x = 1 96 | } else for( i in fnd ) if( short !~ fnd[i] ) x = 1 97 | if( !x ) return short 98 | } 99 | BEGIN { split(q, a, " ") } 100 | { 101 | if( system("test -d \"" $1 "\"") ) next 102 | print $0 >> tmpfl 103 | if( typ == "rank" ) { 104 | f = $2 105 | } else if( typ == "recent" ) { 106 | f = t-$3 107 | } else f = frecent($2, $3) 108 | wcase[$1] = nocase[$1] = f 109 | for( i in a ) { 110 | if( $1 !~ a[i] ) delete wcase[$1] 111 | if( tolower($1) !~ tolower(a[i]) ) delete nocase[$1] 112 | } 113 | if( wcase[$1] > oldf ) { 114 | cx = $1 115 | oldf = wcase[$1] 116 | } else if( nocase[$1] > noldf ) { 117 | ncx = $1 118 | noldf = nocase[$1] 119 | } 120 | } 121 | END { 122 | if( cx ) { 123 | output(wcase, cx, common(wcase, a, 0)) 124 | } else if( ncx ) output(nocase, ncx, common(nocase, a, 1)) 125 | } 126 | ' $datafile)" 127 | if [ $? -gt 0 ]; then 128 | rm -f $datafile.tmp 129 | else 130 | mv -f $datafile.tmp $datafile 131 | [ "$cd" ] && cd "$cd" 132 | fi 133 | fi 134 | } 135 | # tab completion 136 | # complete -C 'z --complete "$COMP_LINE"' z 137 | --------------------------------------------------------------------------------