How to use grep output as a path for cd?

Use Bash's command substitution $(), you also need -o with grep to only select the matched portion:

cd "$(pip install django | grep -o '/usr.*')"

Note that although you will get away in this case but you should always enclose the command substitution with double quotes so that the shell does not perform word splitting on whitespaces (by default space, tab and newline, depends on the IFS variable in case of bash).


Depending on what you do and don't know beforehand about what pip will output, you might decide to grep for something other than /usr.*.

If you know the directory starts with /usr (and that it appears at the end of the line of output from pip, and that /usr does not appear anywhere on the line before the directory name), then that's a fine choice; heemayl's answer tells you how.

If the reason you know it starts with /usr is that you have just run the command and know the directory you want to change to, I suggest the simpler solution of running the command cd /usr/lib64/python2.7/site-packages. This is less typing even if you don't make use of tab completion.

Otherwise, you might choose a different regexp depending on what you know about the output being parsed. All the alternatives below still assume the directory name appears at the end of the line, but the other assumptions vary.

If you know the directory name is absolute (i.e., starts with a /) and no / appears on the line before the directory name, you can use the same regexp as in heemayl's answer but with / instead of /usr:

cd "$(pip install django | grep -o '/.*')"

This matches a / followed by zero or more (*) of any character (.).

If you know the directory name contains no horizontal whitespace (no spaces or tabs) and appears at the end of the line, you can use:

cd "$(pip install django | grep -oP '[^\h]+$')"

Here I've used a Perl regexp (-P) because the \h abbreviation (for [:blank:]) makes this easier to type and to read than an equivalent extended regexp (-E). This matches one or more (+) of any character in a class of characters ([ ]) that is not (^) a space or tab (\h).

If you know the directory name is immediately preceded by in surrounded by horizontal whitespace (i.e., padded on both the left and the right with blanks), and that this is the only such occurrence of in on the line, you can use:

cd "$(pip install django | grep -oP '\hin\h+\K.+')"

This uses a zero-width positive look-behind assertion (\K) to match one or more characters (.+) that appear after a space or tab (\h), in, and another one or more spaces or tabs (\h+), without actually including in and the blank spaces surrounding it in the match. Look-around assertions are a feature of Perl regular expressions.

The pattern \h+in\h+\K.+ would have worked also, but we only need to look for one blank before in, regardless of how many are present. In contrast, we must match all the blanks after in, or they wouldn't be discarded by \K and they would be matched as part of the directory name.

If you know the directory name is immediately preceded by the line's last occurrence of in followed by horizontal whitespace, you can use:

set +H
cd "$(pip install django | grep -oP '\hin\h+(?!.*\hin\h.*)\K.*')"
set -H

There, the zero-width positive look-behind assertion itself contains a zero-width negative look-ahead assertion ((?! )).

The ! appears in such a way as to be difficult to escape elegantly; the method I have used to prevent it from triggering shell history expansion before being passed to grep is to temporarily disable history expansion (set +H) before running the command and re-enable it (set -H) afterwards. If you're using this in a script and your script doesn't contain set -H, you don't need to do this as history expansion is enabled automatically only when a shell runs interactively.

Finally, note that none of these, nor heemayl's answer, are actually piping the output of grep to cd (though the output of pip is still being piped to grep). Rather than pipes, the appropriate tool for this job is command substitution.