I want to create a function in my bashrc, cwhich , which will store the result of which $1 in a path var, then cd to it. But this will start a piece of software, such as cwhich python, cwhich blender, etc. I want to cut off the text after the last occurring / and then cd to the valid directory. Its only a minor inconvenience but by finding or seeking solutions to them I hope to become more pragmatic, efficient and knowledgeable. Help is appreciated.
The external tool you want to use for this is dirname
.
So your function would look like this:
cwhich() {
local bin=$(which "$1")
local bindir=$(dirname -- "$bin")
cd -- "$bindir"
}
That being said that's two external tools for this which is two more than you really need here.
You should use either type -p
or command -v
instead of which
. They are both standardized (which
is not) and are both shell built-ins (which
is not) so they are more portable, guaranteed to be there, and going to be faster as they don't spawn an external process. (We can't avoid the sub-shell for those though.)
That makes the function:
cwhich() {
local bin=$(command -v -- "$1")
local bindir=$(dirname -- "$bin")
cd -- "$bindir"
}
That still leaves dirname
though and we don't need to use that for this we can use Shell Parameter Expansion instead and save the external process (and the sub-shell this time):
cwhich() {
local bin=$(command -v -- "$1")
local bindir=${bin%/*}
cd -- "$bindir"
}
It should be noted that dirname
and ${var%/*}
are not strictly identical. There are some corner cases where they differ but for this usage I don't believe any of those corner cases matter. (See this fantastic answer for more discussion about this difference.)
You may notice that there isn't any error checking in this function. We should probably add that now.
cwhich() {
local bin=$(command -v -- "$1")
local bindir=${bin%/*}
{ [ -z "$bin" ] || [ -z "$bindir" ]; } && return
cd -- "$bindir"
}