>From 0a74257b9fb7e02587b6c5553d8bc1b536249a7e Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Sun, 27 Aug 2017 08:16:21 +0100 Subject: [PATCH] env: add --chdir option This is useful when chaining with other commands that run commands in a different context. * NEWS (New features): Document the new option. * doc/coreutils.texi (env invocation): Likewise. * src/env.c (usage): Likewise. (main): Implement the new option. * tests/misc/env.sh: Test the new option. --- NEWS | 3 +++ doc/coreutils.texi | 17 +++++++++++++++++ src/env.c | 20 ++++++++++++++++++++ tests/misc/env.sh | 10 +++++++++- 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index d37195e..60d5ca5 100644 --- a/NEWS +++ b/NEWS @@ -86,6 +86,9 @@ GNU coreutils NEWS -*- outline -*- expr supports multibyte strings for all string operations. + env now has a --chdir option to change to a new working directory before + executing the subsidiary program. + ** Improvements mv --verbose now distinguishes rename and copy operations. diff --git a/doc/coreutils.texi b/doc/coreutils.texi index 8f1cb4c..f127517 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -16909,6 +16909,23 @@ environment. @opindex --ignore-environment Start with an empty environment, ignoring the inherited environment. +@item --chdir=@var{dir} +@opindex --chdir +Change the working directory to @var{dir} before invoking @var{command}. +This differs from the shell built-in @command{cd} in that it starts +@var{command} as a subprocess rather than altering the shell's own working +directory; this allows it to be chained with other commands that run commands +in a different context. For example: + +@example +# Run 'true' with /chroot as its root directory and /srv as its working +# directory. +chroot /chroot env --chdir=/srv true +# Run 'true' with /build as its working directory, FOO=bar in its +# environment, and a time limit of five seconds. +env --chdir=/build FOO=bar timeout 5 true +@end example + @end table @cindex exit status of @command{env} diff --git a/src/env.c b/src/env.c index 63d5c2c..291fbb4 100644 --- a/src/env.c +++ b/src/env.c @@ -33,11 +33,19 @@ proper_name ("Richard Mlynarik"), \ proper_name ("David MacKenzie") +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + CHDIR = CHAR_MAX + 1 +}; + static struct option const longopts[] = { {"ignore-environment", no_argument, NULL, 'i'}, {"null", no_argument, NULL, '0'}, {"unset", required_argument, NULL, 'u'}, + {"chdir", required_argument, NULL, CHDIR}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, {NULL, 0, NULL, 0} @@ -63,6 +71,7 @@ Set each NAME to VALUE in the environment and run COMMAND.\n\ -i, --ignore-environment start with an empty environment\n\ -0, --null end each output line with NUL, not newline\n\ -u, --unset=NAME remove variable from the environment\n\ + --chdir=DIR change working directory to DIR\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -81,6 +90,7 @@ main (int argc, char **argv) int optc; bool ignore_environment = false; bool opt_nul_terminate_output = false; + char const *newdir = NULL; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -103,6 +113,9 @@ main (int argc, char **argv) case '0': opt_nul_terminate_output = true; break; + case CHDIR: + newdir = optarg; + break; case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); default: @@ -154,6 +167,13 @@ main (int argc, char **argv) usage (EXIT_CANCELED); } + if (newdir) + { + if (chdir (newdir) != 0) + die (EXIT_CANCELED, errno, _("cannot change directory to %s"), + quoteaf (newdir)); + } + execvp (argv[optind], &argv[optind]); int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE; diff --git a/tests/misc/env.sh b/tests/misc/env.sh index f2f6ba8..c409630 100755 --- a/tests/misc/env.sh +++ b/tests/misc/env.sh @@ -18,7 +18,7 @@ . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src -print_ver_ env +print_ver_ env pwd # A simple shebang program to call "echo" from symlinks like "./-u" or "./--". echo "#!$abs_top_builddir/src/echo simple_echo" > simple_echo \ @@ -150,4 +150,12 @@ test "x$(sh -c '\c=d echo fail')" = xpass && #dash 0.5.4 fails so check first returns_ 125 env -u a=b true || fail=1 returns_ 125 env -u '' true || fail=1 +# Verify changing directory. +mkdir empty || framework_failure_ +returns_ 125 env --chdir=empty/nonexistent true || fail=1 +curdir=$(env pwd) || fail=1 +test "$curdir" = "$(pwd)" || fail=1 +curdir=$(env --chdir=empty pwd) || fail=1 +test "$curdir" = "$(cd empty && pwd)" || fail=1 + Exit $fail -- 2.7.4