19

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.

gsthina
  • 311

14 Answers14

34

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.

Jos
  • 29,224
  • 5
    Wouldn't cd - do the same thing? – edwinksl Jun 27 '16 at 11:13
  • 6
    @edwinksl yes, but pushd and popd can remember more than one previous path. – Jos Jun 27 '16 at 11:15
  • Nice, that seems pretty useful. – edwinksl Jun 27 '16 at 11:23
  • 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
  • 1
    They are not exclusive to bash, other shells have them, too. – Reinier Post Jun 27 '16 at 15:08
  • 1
    This in combination with ~-navigation is basically how I get around zsh. With zsh, you can set cd to act as a pushd, and the autocd option lets me just type the path without cd. Combined: $ ~-4<enter> and I am in the fourth-last directory I visited. – muru Jun 27 '16 at 15:32
  • @M.T. Thanks; I added that to my answer, for the sake of completeness. – Jos Jun 27 '16 at 20:35
  • 2
    @Jos you misspelled help pusdh – Sergiy Kolodyazhnyy Jun 27 '16 at 20:37
  • I think this answer in combination with setting CDPATH is a good one. By itself, it will still require a lot of typing to set up the initial pushd. – kojiro Jun 28 '16 at 13:27
  • FWIW: I came up with my aliases u for pushd, o for popd, and uo for pushd;popd ~30 years ago, and I've used them ever since. The fact that pushd with no argument swaps the top two dirs on the stack is particularly handy (and is the basis of uo). – Drew Jun 28 '16 at 17:11
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.

Arronical
  • 19,893
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.
parras
  • 91
  • 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 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: http://paste.ubuntu.com/17990874/ – muru Jun 27 '16 at 20:14
  • @muru right, that makes sense too. – Oliphaunt Jun 27 '16 at 20:15
  • i improve it a little by add pushd $old in the start. so i can use popd to go back. up (){ local old="$PWD" pushd $old; for i in $(seq "${1:-1}"); do cd .. done OLDPWD="$old" } – pery mimon Nov 10 '19 at 15:43
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
}
Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497
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.

5

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!

knub
  • 151
  • 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 01 '16 at 14:27
  • https://github.com/bac0n/bash_completion with bash_completion –  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.

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.

Graipher
  • 1,006
  • 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 00: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

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.

skywind3000
  • 111
  • 1
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}
    
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!

tniles
  • 276
  • 1
  • 7
1

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.

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
}
anjanb
  • 101
0

I wrote a script this afternoon to make it easier to change directories.

Usage

When you call cdd and there is more than one sub-directory you need to pick one:

cdd.png

In this screen if you click OK button it is equivalent to:

cd Seven\ Mary\ Three

or:

cd "Seven Mary Three"

When you call cdd and there is only one sub-directory it automatically changes to it:

rick@alien:~/Music/Seven Mary Three$ cdd
rick@alien:~/Music/Seven Mary Three/American Standard$ 

When you call cdd and there are no sub-directories an error is displayed:

rick@alien:~/Music/Seven Mary Three/American Standard$ cdd
No subdirectories
rick@alien:~/Music/Seven Mary Three/American Standard$