160

I have a common command that gets called from within very specific directories. There is only one executable sitting in /bin for this program, and the current working directory is very important for running it correctly. The script affects the files that live inside the directory it is run within.

Now, I also have a custom shell script that does some things in one directory, but I need to call that command mentioned above as if it was in another directory.

How do you do this in a shell script?

Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
Marty Wallace
  • 34,046
  • 53
  • 137
  • 200
  • 2
    possible duplicate of [How do I run a program with a different working directory from current, from Linux shell?](http://stackoverflow.com/questions/786376/how-do-i-run-a-program-with-a-different-working-directory-from-current-from-lin) – jtbandes Nov 01 '14 at 05:12

6 Answers6

333

Use cd in a subshell; the shorthand way to use this kind of subshell is parentheses.

(cd wherever; mycommand ...)

That said, if your command has an environment that it requires, it should really ensure that environment itself instead of putting the onus on anything that might want to use it (unless it's an internal command used in very specific circumstances in the context of a well defined larger system, such that any caller already needs to ensure the environment it requires). Usually this would be some kind of shell script wrapper.

geekosaur
  • 59,309
  • 11
  • 123
  • 114
50
(cd /path/to/your/special/place;/bin/your-special-command ARGS)
bmargulies
  • 97,814
  • 39
  • 186
  • 310
44

You can use the cd builtin, or the pushd and popd builtins for this purpose. For example:

# do something with /etc as the working directory
cd /etc
:

# do something with /tmp as the working directory
cd /tmp
:

You use the builtins just like any other command, and can change directory context as many times as you like in a script.

Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
  • 6
    There's also `cd -` in a POSIX shell to change back to the previous directory. That said, (a) `pushd` and `popd` are really intended for interactive use, and (b) it's not always safe to assume that you can `cd` back where you started, *especially* in complex subsystems which may use restrictive permissions internally (see http://stackoverflow.com/questions/10555284/in-what-way-is-fast-abs-path-dangerous-but-potentially-faster). – geekosaur May 12 '12 at 19:17
  • 3
    Using a subshell is a much better solution – josh123a123 Apr 19 '16 at 14:31
  • For scripting, a subshell is probably a better idea.. However I'm really happy to learn about `popd`. – connorbode Feb 17 '17 at 02:26
  • 1
    Can you please explain what does `:` symbol mean here? – Vadim Kotov Mar 12 '18 at 09:32
  • 2
    @VadimKotov I think it's effectively a no-op. Relevant section of `man bash` reads: `: [arguments]` No effect; the command does nothing beyond expanding arguments and performing any specified redirections. The return status is zero. – boycy Feb 13 '19 at 10:36
  • For anyone interested, look here - https://stackoverflow.com/questions/3224878/what-is-the-purpose-of-the-colon-gnu-bash-builtin – Vadim Kotov Feb 13 '19 at 16:29
30

If you want to return to your current working directory:

current_dir=$PWD;cd /path/to/your/command/dir;special command ARGS;cd $current_dir;
  1. We are setting a variable current_dir equal to your pwd
  2. after that we are going to cd to where you need to run your command
  3. then we are running the command
  4. then we are going to cd back to our variable current_dir

Or

pushd && cd /path/to/your/command/dir && special command ARGS && popd

Courtesy of @apieceofbart and @Konstantin

abc123
  • 17,855
  • 7
  • 52
  • 82
1

You could also use the env command to achieve the same without an extra shell:

env --chdir=/whatever/path -S whatever_command -some -option and any other arguments

Where whatever_command is the command or script to be executed with all the relevant options and argument. All this must follow the -S option of the env command.

The current working directory is only changed for the execvp() system call so, at the end it will be back to its original value.

env is part of the GNU coreutils package and a copy of its manual page can be found here for more details.

Infact you can use env also to manipulate the environment variables and the signal handling only for a specific execution.

EnzoR
  • 3,107
  • 2
  • 22
  • 25
0

Just a tibit helpful info:

This will change the shell directory to ~/project

function mymake() {
    cd ~/project && make $1
}

This won't

function mymake() {
    (cd ~/project && make $1)
}

to run

mymake something
Timo Huovinen
  • 53,325
  • 33
  • 152
  • 143
  • 1
    So essentially use curly braces and not parenthesis to wrap function contents. – god_is_love Nov 18 '22 at 22:44
  • No. This is basically bad bash programming. They are defining a function without a block, using a single set of parenthesis as the expression. Parenthesis create a new shell which will exit, restoring the old shell. If this person wanted to keep future bash programmers from frustration in debugging sessions, they would have done `function mymake() { ( cd ~/project && make $1 ) }` to avoid the easy mistake that the parenthesis are curly braces. – Edwin Buck Feb 18 '23 at 15:17