4

I have multiple parent directories with the same file structure beneath them.

Example:

parent1/suba/subb/
parent2/suba/subb/

When I am in parent1/suba/subb, I would like to change to parent2/suba/subb without doing something like cd ../../../parent2/suba/subb. How can I do this without listing all the subdirectories and ../s?

5

You can use the PWD variable and parameter expansion constructs to quickly apply a text transformation to the current directory.

cd ${PWD/parent1/parent2}

This doesn't have to be exactly a path component, it can be any substring. For example, if the paths are literally parent1 and parent2, and there is no character 1 further left in the path, you can use cd ${PWD/1/2}. The search string can contain several path components, but then you need to escape the slash. For example, to go from ~/checkout/trunk/doc/frobnicator/widget to ~/checkout/bugfix/src/frobnicator/widget, you can use cd ${PWD/trunk\/doc/bugfix/src}. More precisely, the parent1 part is a shell wildcard pattern, so you can write something like cd ${PWD/tr*c/bugfix/src}.

In zsh, you can use the shorter syntax cd parent1 parent2. Again, you can replace any substring in the path (here, this is exactly a substring, not a wildcard pattern).

You can implement a similar function in bash.

cd () {
  local options
  options=()
  while [[ $1 = -[!-]* ]]; do options+=("$1"); shift; done
  if (($# == 2)); then
    builtin cd "${options[@]}" "${PWD/$1/$2}"
  else
    builtin cd "${options[@]}" "$@"
  fi
}

Zsh provides completion for the second argument. Implementing this in bash is left as an exercise for the reader.

  • Great answer! It's also possible to only replace the differing sections in the path without specifying the entire directory name. So assuming that 1 does not appear elsewhere the path for the example, you can do cd ${PWD/1/2}. – stiemannkj1 Sep 26 '14 at 15:24
  • @stiemannkj1 Indeed, I've added a paragraph to expand on this. I've also added a bash function to get zsh-like behavior, which avoids having to type that ${PWD//} stuff. – Gilles 'SO- stop being evil' Sep 26 '14 at 16:01
1

first time

if parent1 ou parent 2 are elsewhere in directory path.

cd $(pwd | sed -e s:/parent1/:/parent2/: )

then if you switch only from those two directory

cd -
  • will bring you back to the dir you jump from.
  • +1 for the cd - tip. – stiemannkj1 Sep 26 '14 at 15:12
1

You can set the target directories to the positional array. For example:

cd ~
mkdir dirtest
cd dirtest
i=0
until [ "$((i=$i+1))" -gt 9 ] 
do mkdir -p parent"$i"/suba/subb
done

That creates a tree modeled after the example in the question, with parents 1-9. I can now:

set -- "$PWD/parent"[0-9]"/suba/subb"
cd "$1"; pwd

OUTPUT

/home/mikeserv/dirtest/parent1/suba/subb

...and because the [0-9] glob expansion is sorted according to locale...

cd "$5"; pwd

/home/mikeserv/dirtest/parent5/suba/subb

cd "$9"; pwd

/home/mikeserv/dirtest/parent9/suba/subb

...works for 0-9. But the shell will likely not sort parent10 after parent9, and will instead sort it after parent1. It will, however, likely sort parent10 after parent09, though. Once you get into double-digits you should use the ${parameter expansion} braces around the number to explicitly reference "${10}" rather than "$1" then 0.

0

One way to do this is to use pwd and sed to replace the differences in the path like this:

cd `pwd | sed 's/parent1/parent2/'`

or like this:

cd $( pwd | sed 's/parent1/parent2/' )

In some cases (like the example) you do not need to specify the entire directory, and you can just replace the differing parts:

cd `pwd | sed 's/1/2/'`
0

My .bahsrc has a function named cd-e (cd-edit).

cd-e (){  PWD=`echo "$PWD" | vipe +'normal $'`;  cd "$PWD"; }

It opens the current directory in vim, with the cursor positioned at the end (because I tend to edit closer to the end).

( Vipe is part of moreutils, or something like:

#!/bin/sh
set -e
trap 'rm -f "$tmp"' exit
tmp=`mktemp`
cat > "$tmp"
</dev/tty vi "$@" "$tmp" >/dev/tty
cat "$tmp"

)

-1

The easiest and most common way to do such stuff is to use an alias:

alias dir1='cd parent1/suba/subb/' 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.