44

I want to run a script to simply change the current working directory:

#!/bin/bash
cd web/www/project

But, after I run it, the current pwd remains unchanged! How can I do that?

63

It is an expected behavior, and already discussed several times.

The script is run in a subshell, and cannot change the parent shell working directory. Its effects are lost when it finishes.

To change directory permanently you should source the script, as in

. ./script
  • 8
    @Sony: Note that you should use return to escape from a script sourced in this way, not exit - they are like shell functions, and exit will exit the shell that sourced the script. – Charles Stewart Dec 19 '11 at 8:19
  • @CharlesStewart In fact, I'm not familiar with sourced scripts. Thank you! – Sony Santos Dec 19 '11 at 12:56
  • 5
    is source ./script the same? – amyassin Dec 19 '11 at 13:04
  • 2
    @amyassin: yes, it is – enzotib Dec 19 '11 at 13:05
  • 2
    1. . and source are equal in bash. 2. we don't need to use ./ before filename if it's in the same directory. It is ok to run only this: . script – sobi3ch Jun 16 '16 at 15:02
19

For small tasks such as this, instead of creating script, create an alias like this,

$ alias cdproj='cd /dir/web/www/proj'

You should add this to your .bashrc file, if you want it set for every interactive shell.

Now you can run this as $ cdproj.

  • 1
    You can also have the script echo the commands to be executed, and then use eval `./script` or eval $(./script) to execute those commands. This is a common approach for commands that need to update the invoking shell's environment. – Keith Thompson Dec 20 '11 at 10:41
  • 2
    Just be very careful about what you output if you are going to go the eval approach. – jw013 Sep 14 '12 at 20:08
13

Use exec bash at the end

A bash script operates on its current environment or on that of its children, but never on its parent environment.

However, this question often gets asked because one wants to be left at the bash prompt in a certain directory after the execution of a bash script from another directory.

If this is the case, simply execute a child bash instance at the end of the script:

#!/usr/bin/env bash
cd desired/directory
exec bash

This creates a new subshell. Type exit to return to the first shell where the script was initially started.

  • Better to just source the script, as in accepted answer: using exec is typically considered the last resort of a scoundrel.. :) – neuronet Aug 16 '16 at 0:18
  • 1
    this trick doesn't work in debian 9 stretch. – vdegenne May 5 '18 at 0:41
  • 3
    This is the wrong way to go about this! – Paused until further notice. Mar 15 at 22:04
  • 4
    Since nobody has detailed the problems with this (I’m looking at you, @Dennis): (1) Each time you run this, it creates a new, persistent bash process. Do it ten or twenty times in a session, and you’ll have 11 to 21 bash processes piled up. This may affect performance, and, if you try to terminate the session cleanly by typing exit (or Ctrl+D), you’ll have to do that 11 to 21 times. (2) Another drawback of using an executable script is that, if you set any shell options (e.g., dotglob or globstar) in your interactive shell session, you will lose them, because you’re starting a new shell. – G-Man Says 'Reinstate Monica' Apr 10 at 16:39
  • 1
    Very nice solution! I've rewritten my alias in bash_profile so now it is a script stored in a separate file. I use the script to go to a newly created temporary folder. And now it is even easier to have a temporary bash session. SRP in action! Thanks! – artyom.razinov Oct 18 at 13:46
8

While there are answers that do the exact action that you want, a more standard method for such purpose is to create symbolic link:

ln -s ~/web/www/project proj   #use full path to dir!

Then you could cd to the directory using the name proj:

cd proj

This method is more flexible because you could access files using the short name without cd:

ls proj/   #note the endslash!
vim proj/file.x
4

If you change between directories far away in the filesystem. I will recommend autojump.

4

Depends on what you're going to do, another solution can be creating a function instead of a script.

Example:

Create a function in a file, let's say /home/aidin/my-cd-script:

function my-cd() {
  cd /to/my/path
}

Then include it in your bashrc or zshrc file:

# Somewhere in rc file
source /home/aidin/my-cd-script

Now you can use it like a command:

$ my-cd
0

Why not use "exec" it seams to do exactly what I wish.

#!/bin/bash

cd someplace
exec bash

~/someplace
  • 1
    Beware of things that seem to be what you want.  (A giant wooden horse!  Just what I wanted!)  Each time you run this, it creates a new, persistent bash process.  Do it ten or twenty times in a session, and you’ll have 11 to 21 bash processes stacked up.  This may affect performance, and, if you try to terminate the session cleanly by typing exit (or Ctrl+D), you’ll have to do that 11 to 21 times. – G-Man Says 'Reinstate Monica' Apr 8 at 4:23
  • I could definitely see where that would be a problem. For me though I'm using it one time, doing the work I need and then exiting.If that's the only drawback I can live with that. On the other hand if there is a better solution, I'm willing to look at it. – paul Apr 10 at 14:48
  • Aidin’s answer to this question, using a shell function, and Sachin Divekar’s answer, using an alias, are (IMO) better solutions than using a script.  P.S. Another drawback of using a script is that, if you set any shell options (e.g., dotglob or globstar), you will lose them, because you’re starting a new shell. … (Cont’d) – G-Man Says 'Reinstate Monica' Apr 10 at 16:05
  • (Cont’d) …  P.P.S.  I just noticed that you are, basically, reiterating Serge Stroobandt’s answer and saying ‘‘Why not do this?’’  At Stack Exchange we expect answers to provide new ideas and/or information, and not just discuss other answers. – G-Man Says 'Reinstate Monica' Apr 10 at 16:05
-1

You can do that using a function or using && The examples bellow installs Zabbix and creates a file with a line inside it.

Ex:

#!/bin/bash

# Create Function:
installZabbix(){
    cd /usr/src/zabbix-4.2.4;
    ./configure --enable-agent;
    make install;
    cd /usr/src/;
    >file;
    echo "Hi, this is a file." >>file;
}

# Call the function:
installZabbix

or:

#!/bin/bash
cd /usr/src/zabbix-4.2.4 && ./configure --enable-agent && make install && cd /usr/src && >file && echo "Hi, this is a file." >>file

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.