no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
— | linux:misc:z_command [2019/10/31 09:05] (current) – created - external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Z: quicker CD ====== | ||
+ | Download z.sh from [[https:// | ||
+ | Note: You have to enter the folder the old way first | ||
+ | |||
+ | <code bash |z.sh> | ||
+ | # Copyright (c) 2009 rupa deadwyler. Licensed under the WTFPL license, Version 2 | ||
+ | |||
+ | # maintains a jump-list of the directories you actually use | ||
+ | # | ||
+ | # INSTALL: | ||
+ | # * put something like this in your .bashrc/ | ||
+ | # . / | ||
+ | # * cd around for a while to build up the db | ||
+ | # * PROFIT!! | ||
+ | # * optionally: | ||
+ | # set $_Z_CMD in .bashrc/ | ||
+ | # set $_Z_DATA in .bashrc/ | ||
+ | # set $_Z_NO_RESOLVE_SYMLINKS to prevent symlink resolution. | ||
+ | # set $_Z_NO_PROMPT_COMMAND if you're handling PROMPT_COMMAND yourself. | ||
+ | # set $_Z_EXCLUDE_DIRS to an array of directories to exclude. | ||
+ | # set $_Z_OWNER to your username if you want use z while sudo with $HOME kept | ||
+ | # | ||
+ | # USE: | ||
+ | # * z foo # cd to most frecent dir matching foo | ||
+ | # * z foo bar # cd to most frecent dir matching foo and bar | ||
+ | # * z -r foo # cd to highest ranked dir matching foo | ||
+ | # * z -t foo # cd to most recently accessed dir matching foo | ||
+ | # * z -l foo # list matches instead of cd | ||
+ | # * z -e foo # echo the best match, don't cd | ||
+ | # * z -c foo # restrict matches to subdirs of $PWD | ||
+ | |||
+ | [ -d " | ||
+ | echo " | ||
+ | } | ||
+ | |||
+ | _z() { | ||
+ | |||
+ | local datafile=" | ||
+ | |||
+ | # if symlink, dereference | ||
+ | [ -h " | ||
+ | |||
+ | # bail if we don't own ~/.z and $_Z_OWNER not set | ||
+ | [ -z " | ||
+ | |||
+ | _z_dirs () { | ||
+ | local line | ||
+ | while read line; do | ||
+ | # only count directories | ||
+ | [ -d " | ||
+ | done < " | ||
+ | return 0 | ||
+ | } | ||
+ | |||
+ | # add entries | ||
+ | if [ " | ||
+ | shift | ||
+ | |||
+ | # $HOME isn't worth matching | ||
+ | [ " | ||
+ | |||
+ | # don't track excluded directory trees | ||
+ | local exclude | ||
+ | for exclude in " | ||
+ | case " | ||
+ | done | ||
+ | |||
+ | # maintain the data file | ||
+ | local tempfile=" | ||
+ | _z_dirs | awk -v path=" | ||
+ | BEGIN { | ||
+ | rank[path] = 1 | ||
+ | time[path] = now | ||
+ | } | ||
+ | $2 >= 1 { | ||
+ | # drop ranks below 1 | ||
+ | if( $1 == path ) { | ||
+ | rank[$1] = $2 + 1 | ||
+ | time[$1] = now | ||
+ | } else { | ||
+ | rank[$1] = $2 | ||
+ | time[$1] = $3 | ||
+ | } | ||
+ | count += $2 | ||
+ | } | ||
+ | END { | ||
+ | if( count > 9000 ) { | ||
+ | # aging | ||
+ | for( x in rank ) print x " | ||
+ | } else for( x in rank ) print x " | ||
+ | } | ||
+ | ' 2>/ | ||
+ | # do our best to avoid clobbering the datafile in a race condition. | ||
+ | if [ $? -ne 0 -a -f " | ||
+ | env rm -f " | ||
+ | else | ||
+ | [ " | ||
+ | env mv -f " | ||
+ | fi | ||
+ | |||
+ | # tab completion | ||
+ | elif [ " | ||
+ | _z_dirs | awk -v q=" | ||
+ | BEGIN { | ||
+ | q = substr(q, 3) | ||
+ | if( q == tolower(q) ) imatch = 1 | ||
+ | gsub(/ /, " | ||
+ | } | ||
+ | { | ||
+ | if( imatch ) { | ||
+ | if( tolower($1) ~ q ) print $1 | ||
+ | } else if( $1 ~ q ) print $1 | ||
+ | } | ||
+ | ' 2>/ | ||
+ | |||
+ | else | ||
+ | # list/go | ||
+ | local echo fnd last list opt typ | ||
+ | while [ " | ||
+ | --) while [ " | ||
+ | -*) opt=${1:1}; while [ " | ||
+ | c) fnd=" | ||
+ | e) echo=1;; | ||
+ | h) echo " | ||
+ | l) list=1;; | ||
+ | r) typ=" | ||
+ | t) typ=" | ||
+ | x) sed -i -e " | ||
+ | esac; opt=${opt: | ||
+ | *) fnd=" | ||
+ | esac; last=$1; [ " | ||
+ | [ " | ||
+ | |||
+ | # if we hit enter on a completion just go there | ||
+ | case " | ||
+ | # completions will always start with / | ||
+ | /*) [ -z " | ||
+ | esac | ||
+ | |||
+ | # no file yet | ||
+ | [ -f " | ||
+ | |||
+ | local cd | ||
+ | cd="$( < <( _z_dirs ) awk -v t=" | ||
+ | function frecent(rank, | ||
+ | # relate frequency and time | ||
+ | dx = t - time | ||
+ | if( dx < 3600 ) return rank * 4 | ||
+ | if( dx < 86400 ) return rank * 2 | ||
+ | if( dx < 604800 ) return rank / 2 | ||
+ | return rank / 4 | ||
+ | } | ||
+ | function output(matches, | ||
+ | # list or return the desired directory | ||
+ | if( list ) { | ||
+ | cmd = "sort -n >& | ||
+ | for( x in matches ) { | ||
+ | if( matches[x] ) { | ||
+ | printf "%-10s %s\n", matches[x], x | cmd | ||
+ | } | ||
+ | } | ||
+ | if( common ) { | ||
+ | printf "%-10s %s\n", " | ||
+ | } | ||
+ | } else { | ||
+ | if( common ) best_match = common | ||
+ | print best_match | ||
+ | } | ||
+ | } | ||
+ | function common(matches) { | ||
+ | # find the common root of a list of matches, if it exists | ||
+ | for( x in matches ) { | ||
+ | if( matches[x] && (!short || length(x) < length(short)) ) { | ||
+ | short = x | ||
+ | } | ||
+ | } | ||
+ | if( short == "/" | ||
+ | for( x in matches ) if( matches[x] && index(x, short) != 1 ) { | ||
+ | return | ||
+ | } | ||
+ | return short | ||
+ | } | ||
+ | BEGIN { | ||
+ | gsub(" ", " | ||
+ | hi_rank = ihi_rank = -9999999999 | ||
+ | } | ||
+ | { | ||
+ | if( typ == " | ||
+ | rank = $2 | ||
+ | } else if( typ == " | ||
+ | rank = $3 - t | ||
+ | } else rank = frecent($2, $3) | ||
+ | if( $1 ~ q ) { | ||
+ | matches[$1] = rank | ||
+ | } else if( tolower($1) ~ tolower(q) ) imatches[$1] = rank | ||
+ | if( matches[$1] && matches[$1] > hi_rank ) { | ||
+ | best_match = $1 | ||
+ | hi_rank = matches[$1] | ||
+ | } else if( imatches[$1] && imatches[$1] > ihi_rank ) { | ||
+ | ibest_match = $1 | ||
+ | ihi_rank = imatches[$1] | ||
+ | } | ||
+ | } | ||
+ | END { | ||
+ | # prefer case sensitive | ||
+ | if( best_match ) { | ||
+ | output(matches, | ||
+ | } else if( ibest_match ) { | ||
+ | output(imatches, | ||
+ | } | ||
+ | } | ||
+ | ' | ||
+ | |||
+ | [ $? -eq 0 ] && [ " | ||
+ | if [ " | ||
+ | } | ||
+ | fi | ||
+ | } | ||
+ | |||
+ | alias ${_Z_CMD: | ||
+ | |||
+ | [ " | ||
+ | |||
+ | if type compctl >/ | ||
+ | # zsh | ||
+ | [ " | ||
+ | # populate directory list, avoid clobbering any other precmds. | ||
+ | if [ " | ||
+ | _z_precmd() { | ||
+ | (_z --add " | ||
+ | } | ||
+ | else | ||
+ | _z_precmd() { | ||
+ | (_z --add " | ||
+ | } | ||
+ | fi | ||
+ | [[ -n " | ||
+ | precmd_functions[$(($# | ||
+ | } | ||
+ | } | ||
+ | _z_zsh_tab_completion() { | ||
+ | # tab completion | ||
+ | local compl | ||
+ | read -l compl | ||
+ | reply=(${(f)" | ||
+ | } | ||
+ | compctl -U -K _z_zsh_tab_completion _z | ||
+ | elif type complete >/ | ||
+ | # bash | ||
+ | # tab completion | ||
+ | complete -o filenames -C '_z --complete " | ||
+ | [ " | ||
+ | # populate directory list. avoid clobbering other PROMPT_COMMANDs. | ||
+ | grep "_z --add" <<< | ||
+ | PROMPT_COMMAND=" | ||
+ | } | ||
+ | } | ||
+ | fi | ||
+ | </ |