Subdirectory jumper
Posted: Sun Mar 05, 2017 10:09 am
A first stab at a utility whose first version I wrote many years ago for a Windows command processor (then) called 4NT and have used ever since. Its purpose is to make cd'ing around a complex tree of subdirectories faster and easier (I spend my days mostly in CLI). It may help some... but I am actually also very interested to hear from Bash wizards as to how to make this better and more idiomatic.
Basically, j receives a string with the starting letters of a subdirectory to jump to. Say you have /home/Mike/.wine/drive_c/myPrograms/Irfanview/ you can go there via "j /hM.dmI" or via "j ~.dmI" if in /home/Mike or via "j M.dml" if in /home. Obviously, this works better for subdirectories deeper in the hierarchy. "j /es" will just present a menu of the many subdirectories in /etc that start with an s (or any other directory that fits "/e*/s*"). "*" as character is a wildcard, ie matches all directories at that level. The script needs the locate command and works best with an up-to-date database:-).
I've "stolen" a few bits and pieces from various sites (SO et al) though I have in general a pretty good idea what the various commands do. The one thing that's still puzzling me is the xargs bit... I know what it does and I have a fuzzy picture why it works, but not much more. So I am not entirely sure this is the best (or even a safe) way to proceed. The quoting may seem excessive but some of it is required to support directories with spaces in the name. Comments and suggestions welcome.
Basically, j receives a string with the starting letters of a subdirectory to jump to. Say you have /home/Mike/.wine/drive_c/myPrograms/Irfanview/ you can go there via "j /hM.dmI" or via "j ~.dmI" if in /home/Mike or via "j M.dml" if in /home. Obviously, this works better for subdirectories deeper in the hierarchy. "j /es" will just present a menu of the many subdirectories in /etc that start with an s (or any other directory that fits "/e*/s*"). "*" as character is a wildcard, ie matches all directories at that level. The script needs the locate command and works best with an up-to-date database:-).
Code: Select all
j() {
local jcd=""; local sep=${1:0:1}
if [[ $sep == "/" ]]; then
sep=${1:1}
elif [[ $sep == "~" ]]; then
jcd="$HOME"
sep=${1:1}
else
jcd="$(pwd)"
if [[ $jcd == "/" ]]; then
jcd=""
fi
sep=$1
fi
jcd="^$jcd"
for ((i=0;i<${#sep};i++)); do
local c=${sep:$i:1}
if [[ $c == "." ]]; then
c="\."
fi
jcd="$jcd/$c[^/]*"
done
#echo $jcd
jcd=$(locate -r "$jcd$" | xargs -d \\n sh -c 'for i do [ -d "$i" ] && printf "%s\n" "$i"; done' sh {} + )
if [[ -z $jcd ]]; then
echo Nothing found, try again.
return
fi
local oIFS=$IFS
IFS=$'\n'
jcd=($jcd)
IFS=$oIFS
if [[ ${#jcd[@]} > 1 ]]; then
select jcd in "${jcd[@]}"; do break; done
fi
command cd "$jcd"
}