425

Using a Linux shell, how do I start a program with a different working directory from the current working directory?

For example, I have a binary file helloworld that creates the file hello-world.txt in the current directory.

This file is inside of directory /a.

Currently, I am in the directory /b. I want to start my program running ../a/helloworld and get the hello-world.txt somewhere in a third directory /c.

Not A Bot
  • 2,474
  • 2
  • 16
  • 33
Anton Daneyko
  • 6,528
  • 5
  • 31
  • 59
  • 6
    I discovered the hard way that `su` resets the working directory to the home directory of user you specify before running any `-c` commands. This was very helpful to me. – Patrick M Jan 16 '14 at 19:31
  • 7
    It's been 12 years since I've posted this question and today I looked it up myself, cause I could not recall how to do that. – Anton Daneyko Dec 16 '21 at 20:51
  • 2
    It's one thing to come back to a SO post with `a:visited` link and an upvote already on it. It's another thing when you're the asker, or even the answerer. There should be a badge for that... "Forgetful" – Patrick M Dec 16 '21 at 21:20

11 Answers11

670

Call the program like this:

(cd /c; /a/helloworld)

The parentheses cause a sub-shell to be spawned. This sub-shell then changes its working directory to /c, then executes helloworld from /a. After the program exits, the sub-shell terminates, returning you to your prompt of the parent shell, in the directory you started from.

Error handling: To avoid running the program without having changed the directory, e.g. when having misspelled /c, make the execution of helloworld conditional:

(cd /c && /a/helloworld)

Reducing memory usage: To avoid having the subshell waste memory while hello world executes, call helloworld via exec:

(cd /c && exec /a/helloworld)

[Thanks to Josh and Juliano for giving tips on improving this answer!]

Community
  • 1
  • 1
David Schmitt
  • 58,259
  • 26
  • 121
  • 165
117

Similar to David Schmitt's answer, plus Josh's suggestion, but doesn't leave a shell process running:

(cd /c && exec /a/helloworld)

This way is more similar to how you usually run commands on the shell. To see the practical difference, you have to run ps ef from another shell with each solution.

Community
  • 1
  • 1
Juliano
  • 39,173
  • 13
  • 67
  • 73
38

An option which doesn't require a subshell and is built in to bash

(pushd SOME_PATH && run_stuff; popd)

Demo:

$ pwd
/home/abhijit
$ pushd /tmp # directory changed
$ pwd
/tmp
$ popd
$ pwd
/home/abhijit
Marcel Valdez Orozco
  • 2,985
  • 1
  • 25
  • 24
Loren
  • 9,783
  • 4
  • 39
  • 49
  • 2
    A similar suggestion has been done below by Sahil. It does not work if the command fails. Consider `pushd SOME_PATH && run_stuff && popd` -- if run_stuff fails, than popd is not going to be executed. – Anton Daneyko Jul 15 '15 at 16:58
  • Late reply, that depends on the settings of the bash file. Bash can continue executing commands even after a failed command (unlike using &&), but it can be set to not do that using ``set -e`` in the file and then it would fail to ``popd``. – Loren Apr 22 '16 at 20:48
  • 9
    Still, I think `pushd "${SOME_PATH}" && run_stuff; popd` is better than the current answer, since the pushd/popd semantics were specifically designed for this situation of going into some directory and then coming back to the original one. – Marcel Valdez Orozco Nov 29 '16 at 01:40
  • How does it work as defined as alias and I need to pass a param? – DrB Apr 07 '17 at 08:37
  • I think you'd need to write a shell script to which you would pass the parameter that would execute the series of commands as you can't pass a parameter in the middle of an alias. If you need help writing that, you should ask a separate question and reference this one. Once you have the shell script, you could write an alias to call your new script. – Loren May 08 '17 at 19:31
  • Actually, you could use a bash function rather than a shell script, but you still can't use an alias. – Loren May 08 '17 at 19:37
  • How is it different from a regular `cd` ? Is it more protable ? Edit: Fount an answer here : https://unix.stackexchange.com/questions/272965/pushd-popd-vs-cd-cd-in-bash-and-zsh – cassepipe Apr 15 '23 at 10:08
  • 1
    But ... the parentheses create a subshell. – tripleee Apr 17 '23 at 13:04
21
sh -c 'cd /c && ../a/helloworld'
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
mihi
  • 6,507
  • 1
  • 38
  • 48
14

Just change the last "&&" into ";" and it will cd back no matter if the command fails or succeeds:

cd SOME_PATH && run_some_command ; cd -
Vinoth Krishnan
  • 2,925
  • 6
  • 29
  • 34
johnnybravo
  • 141
  • 1
  • 2
9

I always think UNIX tools should be written as filters, read input from stdin and write output to stdout. If possible you could change your helloworld binary to write the contents of the text file to stdout rather than a specific file. That way you can use the shell to write your file anywhere.

$ cd ~/b

$ ~/a/helloworld > ~/c/helloworld.txt
Neuron
  • 5,141
  • 5
  • 38
  • 59
5

why not keep it simple

cd SOME_PATH && run_some_command && cd -

the last 'cd' command will take you back to the last pwd directory. This should work on all *nix systems.

Sahil
  • 489
  • 6
  • 12
4

One way to do that is to create a wrapper shell script.

The shell script would change the current directory to /c, then run /a/helloworld. Once the shell script exits, the current directory reverts back to /b.

Here's a bash shell script example:

#!/bin/bash
cd /c
/a/helloworld
Jin Kim
  • 16,562
  • 18
  • 60
  • 86
2

If you always want it to go to /C, use an absolute path when you write the file.

Tom Ritter
  • 99,986
  • 30
  • 138
  • 174
1

The following worked for my simple need to set up an alias to which I can append an argument, without having to put the instructions in a function; worked in Bash and ZSH:

$ CWD=/your/target/dir command args

My use case: I have a shell script named run-service that resolves paths to other files based on its own location. If I call it with cd ~/Code/company/scripts && run-service dev/some-service, it will expect to find a config file in ~/Code/company/services/dev/some-service. So instead of always having to cd into the directory and calling the script, I just did this:

# Alias definition
alias run-service="CWD=/your/target/dir run-service"

# Calling the alias
$ run-service foo

It's probably too simplistic to be of general use, but it works for my basic use-case.

mmieluch
  • 418
  • 5
  • 10
-1

If you want to perform this inside your program then I would do something like:

#include <unistd.h>
int main()
{
  if(chdir("/c") < 0 )  
  {
     printf("Failed\n");
     return -1 ;
  }

  // rest of your program...

}
Harold
  • 228
  • 2
  • 6
  • He wants to do that in a shell-script, and not in a C. Also, it would be a horrible idea to subprocess the binary file. –  Jan 10 '15 at 03:09