16

We know that using cd <directory> will open the directory, if it exists!

Also, cd .. will take us up one level from the current working directory.

But, when we have a nested dir with longer path like /home/thina/teams/td/tech/app/release/apks, it is tiring to just go into the folder apks and also it is hard to get back to another node, say here /home/thina/teams.

Is there any way to skip the typing of cd and cd ..? I'm using Ubuntu 16.04.

  • Yep! Is there any way to skip the typing of cd and cd .. ? – gsthina Jun 27 '16 at 9:50
  • @GSURENDARTHINA I guess you know you can save at least a few keystrokes by going back multiple levels at once, e.g. in your case cd ../../../../.. – underscore_d Jun 27 '16 at 13:11
  • 2
    Are symlinks an option? – Pockets Jun 27 '16 at 14:59
  • 1
    You might also want to look at the CDPATH variable in the bash docs. – chepner Jun 27 '16 at 16:49
  • Just in case you didn't realize: you can do "cd <directory>" for any directory in the current working directory - just don't start with a slash. So for your example, if your working directory is currently "/home/thina/teams/td/tech/app/release" you would just type "cd apks" – jcadcell Jun 27 '16 at 19:55

13 Answers 13

30

There is pushd and popd:

pushd /home/thina/teams/td/tech/app/release/apks
# current directory now /home/thina/teams/td/tech/app/release/apks
popd
# current directory now what it was before pushd command

Try help pushd and help popd for more options. There is no man page, because pushd and popd are bash built-in commands.

| improve this answer | |
  • 5
    Wouldn't cd - do the same thing? – edwinksl Jun 27 '16 at 11:13
  • 5
    @edwinksl yes, but pushd and popd can remember more than one previous path. – Jos Jun 27 '16 at 11:15
  • 8
    Don't forget dirs to list your directory stack within the pushd/popd commands. – Arronical Jun 27 '16 at 12:02
  • 4
    These are covered in the manual page for bash-builtins(7) since they are bash built-in commands. (Or they can also be found in the full manual page for bash ) It is the same info as the help pushd and help popd you mentioned (as well as help dirs) but I thought I'd mention that in case people were wondering where these commands come from. – M. T. Jun 27 '16 at 13:12
  • 2
    @Jos you misspelled help pusdh – Sergiy Kolodyazhnyy Jun 27 '16 at 20:37
16

In addition to the very good answers already provided, here are some tips on using cd effectively.

  • cd - will take you back to the last directory you were in.
  • cd ../../.. will take you up 3 levels at once, you can use the .. notation chained together to 'move up' as many directories as you like.
  • If you're not sure how many times you wish to move up, use cd .., then use bash history by pressing up on the arrow key to use the command again.
  • Use ~ to stand in for the current users home directory, if you're logged in as the user thina, cd ~/teams, will take you to /home/thina/teams
  • Use Bash auto-completion for paths, the tab key will complete a section of a path in the cd command, if you type part of a path segment followed by Tab, that segment will be completed if there's no other valid choice. For instance, if you had typed cd /home/thina/teams/td/t then pressed Tab, the word tech would be filled in for you, so long as there were no other files or directories in the td directory that started with the letter t.

Using these tips together can make traversing directories with cd far less painful.

| improve this answer | |
  • 2
    Adding to the point on ~, particularly if you are root, ~user will quickly get you to user's home directory. – a CVn Jun 27 '16 at 14:33
  • Thanks, I didn't realise that, I'll add it in the next edit. – Arronical Jun 27 '16 at 14:45
9

To go up in the tree several levels at a time, you can use the following function (thanks to muru for the enhanced version):

up ()
{
    local old="$PWD"
    for i in $(seq "${1:-1}"); do
        cd ..
    done
    OLDPWD="$old"
}

Then you can do:

$ pwd
/home/thina/teams/td/tech/app/release/apks
$ up 5
cd'ing into /home/thina/teams

Additionally:

  • calling up without an argument is equivalent to cd .. due to ${1:-1} which substitutes $1 when set and 1 otherwise
  • setting OLDPWD after the last cd .. aims at preserving the usual cd - behavior.
| improve this answer | |
  • 1
    Technically, this is a function, not an alias. – Reinier Post Jun 27 '16 at 15:09
  • @ReinierPost: Right enough! I've corrected accordingly. – parras Jun 27 '16 at 15:17
  • 2
    Suggestions: -gt instead of >. > is lexicographic, it compares as strings. Also, instead of building a path, why not do cd .. in a loop: for i in $(seq "${1:-1}"); cd ..; done? That can eliminate the if condition too. – muru Jun 27 '16 at 15:36
  • @muru I agree with your gt remark, but regarding your second suggestion, see the final bullet in the answer. Makes sense to me. – Oliphaunt - reinstate Monica Jun 27 '16 at 20:10
  • 1
    @Oliphaunt that's not particularly difficult, you just set OLDPWD to the original path. Here's a complete version: paste.ubuntu.com/17990874 – muru Jun 27 '16 at 20:14
7

For long directory names, use variables with full path. For example,

APKS="/home/thina/teams/td/tech/app/release/apks"

Then you can do just cd "$APKS"

As for going up x number of directories, I have this function defined in my .bashrc

goup() # go up x number of dirs
{
  num=$1
  while [ $num -ne 0  ];do
    cd ..
    num=$( expr $num - 1   )
  done
}

To return to /home/thina/teams from apks you would do

goup  6

Here's an example of usage:

$> pwd
/sys/class/backlight/intel_backlight
$> goup 3
$> pwd
/sys
$> 

Another small function that i came up with, but never used as much is bookmark function.

Here's how it works: it saves your current folder to some file, and then you can cd to a specific directory based on the line number in that file. Example:

$> cd /etc/lightdm
$> bookmark
$> cat ~/.dirsbookmarks                                                                                                  
/home/xieerqi
/sys/class/backlight
/etc/lightdm
$> cd $( awk 'NR==2' ~/.dirsbookmarks  )                                                                                 
$> pwd
/sys/class/backlight

And here is the function itself:

bookmark()
{ # bookmarks current dir
  pwd >> $HOME/.dirsbookmarks
}
| improve this answer | |
5

UPDATE: There's an even more powerful tool than autojump: fasd, but I am not familiar with it.


I am surprised no one has mentioned autojump yet which

works by maintaining a database of the directories you use the most from the command line (Directories must be visited first before they can be jumped to.)

It's basically what @graipher has built, with a few extra options.

As I have mentioned on another question:

After you cd a few times to a directory (even once suffices):

cd /home/thina/teams/td/tech/app/release/apks

you can use the shortcut j to move there quickly, regardless of which directory you're currently in:

j apks

Note that using any part of the path works, as long as it's the highest on the list: j app will also take you to .../apks if you went there more times than to .../app.

I would recommend it instead of having your own script since it is well maintained, distributed for Ubuntu, and has other neat features, such as jump to child:

.../td/tech $ jc apk
.../release/apks $ 

Has moved you to apks in td, rather than some other apks under a different tree.

| improve this answer | |
  • +1 for 'fasd'. It's really useful. – Thomas Dec 10 '18 at 18:46
4

Aliases

I have a list of frequently used directories directly available via alias. This also includes shortcuts for the directories up the hierarchy.

alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'
alias .....='cd ../../../..'
alias cdwork=/home/knub/Repositories/work
alias cduni=/home/knub/University

Now, when I want to go three levels up, I just type ....<Enter> and there I am!

| improve this answer | |
  • I like this too, because even though at first I thought "hmm 4 periods for 3 levels..." then I thought, "Oh yeah... Computers! 0, 1, 2, 3!" :D Now easy to remember, useful, and something I'll be playing with as well. Cheers! – P Smith Jul 1 '16 at 14:27
  • github.com/bac0n/bash_completion with bash_completion – bac0n Sep 13 '19 at 11:45
4

Turn on the autocd option (shopt -s autocd), so that you don't have to type cd. For example, you just need the two-character command .. to go to the parent directory.

If you're navigating between two directories, you can toggle between them with cd -, which goes to the previous working directory. The autocd option doesn't make - run cd - but you can define an alias or function for that.

You can memorize directories on a stack with the builtins pushd and popd. The builtin dirs lists the directory stack (I find dirs -v more readable).

If you frequently change to subdirectories of a particular directory, and these subdirectories have rather unique name, add them to the CDPATH variable. However be warned that I've never found a situation where CDPATH was actually handy.

You can set a variable to a directory name and then change to it with $foo.

Zsh Install zsh has a few nice features that bash doesn't have. Some of them can be emulated by writing functions that do the same job. In particular the two-argument form of cd lets you conveniently change to another directory with a similar name, e.g. from /home/thina/teams/td/tech/app/release/apks/com.acme/v1, running cd release beta goes to /home/thina/teams/td/tech/app/beta/apks/com.acme/v1.

| improve this answer | |
2

As I already answered on a related question on UnixSE, I use a script called z [github] for this.

It remembers directories you cd to, ranks them according to frecency (frequency + recency) and allows you to change to one of the remembered paths using some part of its name.

After having cd'ed to a directory at least once you can do e.g instead of:

$ cd ~user/very/long/path/with/many/subfolders/

Just do:

$ z sub

which will work, using partial name matching (assuming you have no other directory containing in its path the term sub and which has a higher frecency).

I also defined a function like this, which first tries a normal cd and if that fails uses z:

function cd() {
    builtin cd "$1" 2> /dev/null || z "$1" || (echo "cd: File or Directory not found: $1" >&2 && exit 1)
}

This gives you the best of both. If the folder is in the current directory or a valid full path is given, it will just cd there, but if not it will try to find a match in the database and cd there. This takes away the (small) pain of sometimes having to use cd (to train the database, going to a folder you have never been to before) and sometimes remembering to use z, when applicable.

| improve this answer | |
  • Are you sure this cd of yours doesn't interfer with how z builds up the database of frequently visited directories? – leftaroundabout Jun 27 '16 at 18:41
  • how is it different from autojump ? – Ciprian Tomoiagă Jun 28 '16 at 0:44
  • @leftaroundabout: Not sure, but so far it has been working nicely. z definitely builds the database whenever you use the builtin cd (which my setup tries first). Not so sure whether the database is updated when the z part is used, though. EDIT: Just tested whether the database is updated when doing a $ builtin cd ~/folder/i/have/not/been/to/yet/. It is. – Graipher Jun 28 '16 at 13:17
  • 1
    @CiprianTomoiaga Indeed, it seems to do basically the same thing. The overwrite of the cd command I use could also be used for that. autocomplete's different commands seem interesting, though! – Graipher Jun 28 '16 at 13:22
  • btw: I'm not the author of z, just find it very useful. – Graipher Jun 28 '16 at 13:24
1

Three more options that I find to work well (though I may in the future use pushd more, I only just learned about that):

  • Arrange your paths so you don't need to cd into deeply nested directories in the first place, or rather: so the locations that you need to visit often are right at your fingertips. The way to achieve this is with symlinks: keep the explicit, well-hierarchised directories as they are, but make a quick-access link for your own convenience.

    ln -s ~/teams/td/tech/app/release/apks ~/apks
    

    Then, instead of typing the long path to cd, just use cd ~/apks, and cd ../teams (or, in that example preferrable, ~/teams) to get back.

  • Don't use a single shell and cd back and forth between paths, but keep one shell running for each of the paths you needs to work in. There are multiple levels on which to achieve this multitasking:

    • Use multiple terminal windows. Works best if the windows live on different workspaces.
    • Use multiple tabs in a single window. This is paticularly well-suited for only doing a few commands in some directory: to get back, simply close the terminal tab!
    • (Not really sensible IMO, but for completeness:) use a terminal multiplexer like tmux.
    • Just launch an action in a single-purpose command that cds down into the folder, does one thing there and immediately gives back control on the original folder: instead of

      $ cd /home/thina/teams/td/tech/app/release/apks
      $ some_command this_file_here
      $ cd ../../../../..
      

      simply do the one-liner

      $ (cd ~/teams/td/tech/app/release/apks; some_command this_file_here)
      

      or equivalently

      $ sh -c 'cd ~/teams/td/tech/app/release/apks
      > some_command this_file_here'
      
  • Don't cd at all, but simply execute the command right from your home directory. Brace expansions can help a lot here: Instead of

    $ cd /home/thina/teams/td/tech/app/release/apks
    $ some_command this_file_here other_file_also_apks
    $ cd ../../../../..
    

    you can do

    $ some_command ~/teams/td/tech/app/release/apks/{this_file_here,other_file_also_apks}
    
| improve this answer | |
1

Pushd and Popd

The commands pushd and popd are favorites of mine. The pushd command will remember the directories you've visited, viewable with the command dirs, and when you're ready to jump backwards use popd to return.

Here's an example using bash functions and aliases:

sd ()
{
    pushd "$1" > /dev/null
}

po ()
{
    popd
}

alias d='dirs'

I constantly use a mix of these commands in a variety of ways.

Aliases

Another option for frequently accessed directories is to simply alias the cd or pushd commands. So, using the examples from your post:

alias cdapks='cd /home/thina/teams/td/tech/app/release/apks'
alias cdteams='cd /home/thina/teams'

Combination

Combine the two ideas and you can even have this:

alias sdapks='sd /home/thina/teams/td/tech/app/release/apks'
alias sdteams='sd /home/thina/teams'

Which then gives you a lot of flexibility in traversing directories. I keep the cd*** and sd*** aliases on hand for things like Desktop, Documents, Music, Downloads, etc. and it's very handy!

| improve this answer | |
1

Try z.lua - A new cd command that helps you navigate faster by learning your habits.

  • cd to a directory contains foo:

    z foo
    
  • cd to a directory ends with foo:

    z foo$
    
  • use multiple arguments:

    Assuming the following database:

    10   /home/user/work/inbox
    30   /home/user/mail/inbox
    

    "z in" would cd into /home/user/mail/inbox as the higher weighted entry. However you can pass multiple arguments to z.lua to prefer a different entry. In the above example, "z w in" would then change directory to /home/user/work/inbox.

  • cd with interactive selection:

    When there are multiple matches found, using z -i will display a list:

    $ z -i soft
    3:  0.25        /home/data/software
    2:  3.75        /home/skywind/tmp/comma/software
    1:  21          /home/skywind/software
    > {CURSOR}
    

    Then you can input the number and choose where to go before actual cd. eg. input 3 to cd to /home/data/software. And if you just press ENTER and input nothing, it will just quit and stay where you were.

    z.lua also supports fzf for interactive selection or argument completion:

    completion with fzf

  • fast go back to parent without typing cd ../../..:

    New option "-b" can quickly go back to a specific parent directory in bash instead of typing "cd ../../.." redundantly:

    • (No argument): cd into the project root, the project root the nearest parent directory with .git/.hg/.svn in it.

    • (One argument): cd into the closest parent starting with keyword, if not find, go to the parent containing keyword.

    • (Two arguments): replace the first value with the second one (in the current path).

    ...

    Let's start by aliasing z -b to zb:

    # go all the way up to the project root (in this case, the one that has .git in it)
    ~/github/lorem/src/public$ zb
      => cd ~/github/lorem
    
    # cd into to the first parent directory named g*
    ~/github/vimium/src/public$ zb g
      => cd ~/github
    
    # substitute jekyll with ghost
    ~/github/jekyll/test$ zb jekyll ghost
      => cd ~/github/ghost/test
    

Wish it could fit your need.

| improve this answer | |
0

fish has several nice facilities for quickly moving around.

  • If you type c d right-arrow enter, it repeats the most recent cd.
  • By using c d up-arrow right-arrow enter, it repeats the second-most recent cd.
  • Etc.
  • It has prevd and nextd, which are often easier to use than pushd and popd.

Also, I keep my favourite directories symlinked to ~/f, so I can cd ~/f/x to get to ~/foo/bar/baz/experimental-data.

| improve this answer | |
0

I've long used aliases for frequently accessed directories.

I also have a bash function called ccb(short for create cd bat file -- this originated in dos/windows where the .bat shell script ccb.bat would create another .bat file for jumping to the current directory)that creates/appends aliases(in the .bash_aliases file) to the current directory.

eg : $ ccb myfav will create an alias to the current directory with an alias myfav in the .bash_aliases file and source the .bashrc file so the alias is immediately available.

I just now found a new solution. It's a bash function

## USAGE : lj <your_dir>
### lj -- short for LongJump -- (kinda similar to a C function which would jump to an address outside of your current function)
function lj() {
        pushd `find . -type d -name $1 -print | head -n 1`
}

$ lj deeply_nested_dir_name

this doesn't need to learn anything from previous usage. The problem that this might not solve is : if there are more than 1 directories named "deeply_nested_dir_name" in the sub-directory tree, then it will jump to the 1st of the directory found by find.

Also, this solution will not be able to goto some other directory tree.

between hardcoded aliases and generated aliases and this new lj() function, most of my needs are taken care of.

Here's my ccb() bash function for anyone who wants to use it

function ccb() {
        foo=$PWD
        echo "" >> ~/.bash_aliases
        echo "alias $1='pushd $foo > /dev/null'" >> ~/.bash_aliases
        source ~/.bashrc
}
| improve this answer | |

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.