I have a common use case that I'd like to write a function for: I often want to cd to some directory relative to some file.
$ gem which rspec/core | xargs echo -n | pbcopy
$ cd *paste and delete end until direcory looks right*
note: gem which rspec/core
prints something like "/Users/joshcheek/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.10.0/lib/rspec/core.rb"
$ gem which rspec/core | 2dir 3
Which will cd me into "/Users/joshcheek/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.10.0" (passing the argument "3" tells it to remove "lib/rspec/core.rb" from the end)
2dir() {
read dir
for i in $(seq 1 $1)
do
dir="${dir%/*}"
done
cd "$dir"
}
But the cd changes the function's directory, not mine. I've tried swapping it with an alias, but can't figure out how to make anonymous functions or pass the argument.
I'd use:
2dir()
{
name=${2:?'Usage: 2dir count path'}
count=$1
while [[ $count -gt 0 ]]; do name=$(dirname "$name"); ((count--)); done
cd "$name"
}
and use it as:
2dir 3 $(gem which rspec/core)
This works where your pipeline can't. The cd
in the pipe process affects that (sub-)shell, but cannot affect the current directory of the parent process. This function can be made to work.
And you can use your dir="${dir%/*}"
in place of my dirname
if you prefer, except that you'll end up in your home directory instead of the current directory (or root directory, depending on whether you gave a relative or absolute path name) if you specify 10 when there are only 5 components.
Here's a variant of @Jonathan Leffler's suggestion to streamline usage a little -- it makes the count argument optional, and avoids the need for $( )
around the command:
2dir() {
# If first arg is a number, use it as a trim count; otherwise assume 2
if [[ "$1" =~ ^[0-9]+$ ]]; then
count="$1"
shift
else
count=2
fi
if [[ $# -lt 1 ]]; then # Make sure a command was specified
echo "Usage: 2dir [count] command [commandargs ...]" >&2
return 1
fi
name="$("$@")" # Execute the remaining args as a command to get the target directory
while [[ $count -gt 0 ]]; do name=$(dirname "$name"); ((count--)); done
cd "$name"
}
Example uses:
2dir 3 gem which rspec/core
2dir gem which rspec/core
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With