We have env(1) to modify the environment of the command we want to run (for example env MANPAGER=more man dtrace). Is there something similar but for modifying the directory that the command is going to be started in?

Ideally, I would like it to look like this:

theMagicCommand /new/cwd myProgram

This way it could be "chained" with other env(1)-like commands, e.g.,

daemon -p /tmp/pid env VAR=value theMagicCommand /new/cwd myProgram

So far I can think of the following solution, which unfortunately does not have the same interface as env(1):

cd /new/cwd && myProgram

Also, I can just create a simple shell script like this:

#! /bin/sh -
cd "${1:?Missing the new working directory}" || exit 1
shift
exec "${@:?Missing the command to run}"

but I am looking for something that already exists (at least on macOS and FreeBSD).

myProgram is not necessarily a desktop application (in which case I could just use the Path key in a .desktop file).

  • 6
    Why does cd /new/cwd && env VAR=value myProgram not meet your critera? – jpaugh Nov 9 at 19:27
  • That's already in the question, where M. Piotrowski explained that that is not the same interface as env. Look at env. Compare it to rtprio, idprio, numactl, jexec, chrt, and indeed the commands in the toolsets mentioned in the answers. There's a pattern, and it is chain loading. – JdeBP Nov 10 at 0:08
  • 3
    What do you mean by “interface”? And why not use (cd the/cwd; cmd)? – Konrad Rudolph 2 days ago
  • 2
    @KonradRudolph For example, you cannot easily pass (cd the/cwd; cmd) to env(1) without wrapping it with sh(1). – Mateusz Piotrowski 2 days ago
up vote 18 down vote accepted

AFAIK, there is no such dedicated utility in the POSIX tool chest. But it's common to invoke sh to set up an environment (cwd, limits, stdout/in/err, umask...) before running a command as you do in your sh script.

But you don't have to write that script in a file, you can just inline it:

sh -c 'CDPATH= cd -P -- "$1" && shift && exec "$@"' sh /some/dir cmd args

(assuming the directory is not -). Adding CDPATH= (in case there's one in the environment) and -P for it to behave more like a straight chdir().

Alternatively, you could use perl whose chdir() does a straight chdir() out of the box.

perl -e 'chdir(shift@ARGV) or die "chdir: $!"; exec @ARGV or die "exec: $!"
         ' /some/dir cmd args
  • Oh, yeah. This is indded a very handy variation of the script I included in my question. I was afraid that the utility I am looking for does not exist since its functionality is already available with a relatively short sh(1) oneliner. – Mateusz Piotrowski Nov 9 at 15:17
  • 8
    If you're already running sh, you can also do (cd /wherever && exec /my/command). The () implicitly opens a subshell to run the wrapped commands, and of course, exec gets rid of the extra shell process as quickly as /my/command starts running. – jpaugh Nov 9 at 19:24
  • 1
    That was suggested in a now-deleted answer. The questioner explained that that was not an answer to what xe asked. – JdeBP Nov 10 at 0:22

The toolsets used in the daemontools world, and elsewhere, have this and more besides; have had for many years; and are widely available.

  • Wayne Marshall's perp has runtool:

    runtool -c /new/cwd myProgram
  • Laurent Bercot's execline has cd:

    cd /new/cwd myProgram
  • my nosh toolset has chdir:

    chdir /new/cwd myProgram

All of these are chain-loading tools, designed to be used in exactly these sorts of chains. There is a wide selection of chain-loading tools in these toolkits for other purposes.

Further reading

There is such a popular program. It is called ... hold onto your chair... drumroll... env. The GNU version, since version 8.28, not POSIX, has the -C option which lets you set the directory just as you require:

    NAME
           env - run a program in a modified environment

    SYNOPSIS
           env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]

    DESCRIPTION
           Set each NAME to VALUE in the environment and run COMMAND.

           Mandatory arguments to long options are mandatory for short options too.

           -i, --ignore-environment
                  start with an empty environment

           -0, --null
                  end each output line with NUL, not newline

           -u, --unset=NAME
                  remove variable from the environment

           -C, --chdir=DIR
                  change working directory to DIR

           --help display this help and exit

           --version
                  output version information and exit

           A mere - implies -i.  If no COMMAND, print the resulting environment.

  • Cool, although it is not available out-of-the-box on macOS and FreeBSD. – Mateusz Piotrowski yesterday

Certain programs have an option for this, like Git:

-C <path>

Run as if git was started in <path> instead of the current working directory.

and Make:

-C dir, --directory=dir

Change to directory dir before reading the makefiles or doing anything else.

and Tar:

-C, --directory=DIR

Change to DIR before performing any operations. This option is order-sensitive, i.e. it affects all options that follow.

  • Yes. Although my question is what if myProgram does not provide such an option... Thank you for your contribution but I'm afraid it does not answer my question at all. – Mateusz Piotrowski 2 days ago

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.