9

For example I'm in my directory:

/home/myname

and then I want to CD into a different directory.

/home/pulsar/... 

Since I need to go pretty deep into the other directory, how can I go about this without having to type the whole line? I tried

cd */thedirectoryiwanttogointo

but that doesn't work. I have to type the whole line.

JobHunter69
  • 940
  • 5
  • 12
  • 22
  • 3
  • Could you [edit] with more details of what you're trying to do? Do you mean cd */foo to mean "find a directory called foo anywhere on the system and cd to it"? – Michael Homer Nov 07 '15 at 04:17
  • @ Michael Yes that's what I'm trying to do. Will * not work for that? – JobHunter69 Nov 07 '15 at 04:18
  • @eyoung I have been using Tab Completion but with so many nested directories and similar names in this computer cluster, it hasn't been very useful. – JobHunter69 Nov 07 '15 at 04:20
  • Well, what do you expect to happen if there's more than one directory with that name? How long do you expect it to take to find it? – Michael Homer Nov 07 '15 at 04:21
  • As you've found already, no, it won't work as is, but depending on the effect you want there might be another way to get where you want to go. (The reason it doesn't work is that * expands where it is, which is the current directory when it's at the start of the path - consider, say, *.txt) – Michael Homer Nov 07 '15 at 04:22
  • I'd expect an error if there's more than one directory, but there is only one file with such a name. And what do you mean by .txt? Do I type .txt/foo ? – JobHunter69 Nov 07 '15 at 04:24
  • If */foo expanded to the path to foo found anywhere on the system, *.txt would have to expand to every .txt on the system. Paths that don't start with a / are always treated as relative to the current directory. If there is a file ./x/foo then */foo will expand to the (relative) path to it, and you could cd to that. Searching the entire system would at the least be very time-consuming. There may be some other way of accommodating your workflow, though. – Michael Homer Nov 07 '15 at 05:30
  • cd **/foo should work in zsh. – sendmoreinfo Nov 07 '15 at 11:40

4 Answers4

6

Probably your wildcard does not work because:

  • there were no matches for the wildcard from the location you gave, or
  • there was more than one match.

The usual approach (in a shell) to moving frequently among subdirectories is to use the CDPATH feature, as well as pushd and popd.

The CDPATH feature (perhaps first seen in tcsh) is a colon-separated list of directories. If the parent of your thedirectoryiwanttogointo name is reasonably unique, then you could add the parent to the list.

For further reading (your shell's manual page should be first):

pushd and popd are newer than CDPATH, but still dating from the mid-1990s. They allow you to save your current directory ("pushing" onto a stack) and restore it ("popping" from a stack) during their respective cd commands. For further reading:

Other people use shell aliases or symbolic links. Those are most useful when going to well-known locations.

Thomas Dickey
  • 76,765
5

Assuming all the possible target directories are under /home and there's no newline characters in directory names, you might use this shell function:

cds() {
    cd "$(find /home -type d -name "$1" | head -n 1)"
}

$ cds thedirectoryiwanttogointo

Of course, depending on how many subdirectories and files are under /home and the ability for your OS to cache all the tree in memory or not, performance will vary significantly.

On GNU systems, you can speed it up and make it more reliable wrt newline characters in file names by using this syntax instead:

cds() {
    cd "$(find /home -type d -name "$1" -print -quit)"
}

That will stop searching as soon as the first match is found.

Note that the argument is taken as a pattern, so you can do:

cds 'foo*bar'

for instance to cd into the first directory (the order is not specified) whose name starts with foo and ends in bar.

jlliagre
  • 61,204
2

You want wildcard expansion to find a path anywhere on the system. You can do that, if you specify the pattern correctly:

cd /**/thedirectoryiwanttogointo

will work in zsh and fish by default, in Bash if you first shopt -s globstar, in tcsh if you set globstar, in ksh93 if you set -o globstar, in yash if you set -o extended-glob.

This works because the wildcard is used within an absolute path starting with / instead of being relative to the current directory, and when you opt into using the ** pattern it expands to any number of subdirectories.

While this will work, it is likely to take an extremely long time. Your shell has to search your entire system for the matching file(s). You can cut that down by providing a longer prefix to trim out more of the search space:

cd /home/pulsar/**/thedirectoryiwanttogointo/

The further you drill down the less searching there will be to do. If the directory tree is fairly sparse, this won't take too long and is actually practical to use. The trailing / ensures that the expansion is only to a directory, which removes one variety of ambiguity that could occur.

If there's more than one match still, the result will depend on your shell. Bash and fish will switch to the alphabetically first match, ignoring the ambiguity. tcsh and yash will report an error. zsh and ksh will interpret it as an attempt to use one of their advanced directory-switching features and probably report an error.


If you're likely to use the same directory repeatedly, either putting the parent into CDPATH or creating a shell variable $FOO you can use in place of the long path is a better option. You can combine the shell variable with ** expansion to save more typing if you're using it often.

Michael Homer
  • 76,565
1

If you're always going to the same deep directory, one simple solution is to just create a symlink to it:

ln -s ~/foo/bar/baz/quux/etc/etc/etc/target ~/shortcut

If you've gone to the directory before, another solution is to search your command history for the name you want; press ctrl-R and the characters to search for. This is bash-specific, but I imagine most modern shells have a similar facility.

Tom Zych
  • 933