zc
is a utility for tracking which directories you have recently
visited. With a little shell integration effort, it permits "jumping
around". The utility was written after some experimentation with
rupa/z.
Relative to rupa/z's z.sh, zc has the following advantages:
- zc isolates maintaining the recently-visited database from shell details.
- zc uses flocks to avoid clobbering the database in, e.g., GNU Screen.
- zc has the overhead like launching one single process.
- zc has decent unit tests (try
make check
). - zc has some minimal performance testing (try
make stress
).
Relative to rupa/z, zc
has the following disadvantages:
- zc must be compiled and you have to read my lousy C.
- The mechanism for cleaning up subsequently removed directories might be unfriendly to network filesystems.
- Regex search is not implemented.
- Bash integration (found below) requires bash-preexec.
- Zero adoption by anyone but me.
After creating some directories and visiting them once, attempting to jump to a directory containing 'q' is ambiguous. The ambiguity is broken by asking for the most recently visited match (-t):
$ mkdir -p foo/bar/baz/qux/quux
$ cd foo/bar/baz/qux/quux/
$ cd ..
$ cd ..
$ cd ..
$ cd ..
$ cd ..
$ z q
zc/foo/bar/baz/qux
zc/foo/bar/baz/qux/quux
$ z -t q
~/Build/zc/foo/bar/baz/qux ~/Build/zc
The above ambiguity could also be settled by providing, e.g., "quu". Instead
of most recent time (-t), one could request highest rank (-r) according to
number of visits or by "frecency"
(-f). Multiple path elements could be used, e.g. ux ux
, and all of them
must match in order.
Notice z
appeared above instead of zc
. That's a consequence of
the following installation.
Installing zc
involves something like the following in your .bashrc
.
# Aliases ease using https://github.com/RhysU/zc against a particular database
if test -x "${HOME}/bin/zc"; then
z_raw() { "$HOME/bin/zc" -d "$HOME/.zc" "$@"; }
z_add() { "$HOME/bin/zc" -d "$HOME/.zc" -a -- "$@"; }
else
z_raw() { echo "RhysU/zc is not installed" 1>&2; false; }
z_add() { :; }
fi
# Run http://github.com/RhysU/zc in some mode against fixed database.
# Whenever it succeeds and only one line is output, attempt to pushd there.
z() {
local zout newline='
'
if zout=$(z_raw "$@"); then
case $zout in
*"$newline"*) echo "$zout" ;; # 2+ matches => display
"") builtin pushd "$@" ;; # No match => use input
*) builtin pushd "$zout" ;; # One match => use match
esac
fi
}
zf() { z -f -- "$@"; } # Abbreviation
zr() { z -r -- "$@"; } # Abbreviation
zt() { z -t -- "$@"; } # Abbreviation
# Z becomes much more useful with tab completion hooks installed.
# Above z() must accommodate trailing slashes because of '-o filenames'.
_z_completion() {
COMPREPLY=()
while IFS=$'\n' read -r line; do
COMPREPLY+=("$line")
done < <(z_raw -k -- "${COMP_WORDS[@]:1}")
}
complete -o filenames -F _z_completion z
# On every command, record the working directory using z_add.
# Versus https://github.com/rupa/z, updating per-command nicer for GNU Screen.
# Also, the updates are lighter weight on account of backing zc implementation.
precmd_z() {
# Only register non-HOME directories as HOME is just a 'cd' away.
if [ "$PWD" != "$HOME" ]; then
z_add "$PWD"
fi
}
# Prompts use precmd/preexec hook per https://github.com/rcaloras/bash-preexec.
if [ -f "${HOME}/.preexec.bash" ]; then
. "${HOME}/.preexec.bash"
precmd_functions+=(precmd_z)
fi
Golfing is most welcome, especially golfing that addresses disadvantages. Not
breaking Bash login on systems without either
bash-preexec or zc
available is
desired.