mirror of
https://https.git.savannah.gnu.org/git/coreutils.git
synced 2026-01-26 15:29:07 +00:00
env: add --chdir option
This is useful when chaining with other commands that run commands in a different context, while avoiding using the shell to cd, and thus having to consider shell quoting the chained command. * 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.
This commit is contained in:
parent
2686052667
commit
57dea5ed07
3
NEWS
3
NEWS
@ -88,6 +88,9 @@ GNU coreutils NEWS -*- outline -*-
|
||||
split supports a new --hex-suffixes[=from] option to create files with
|
||||
lower case hexadecimal suffixes, similar to the --numeric-suffixes option.
|
||||
|
||||
env now has a --chdir (-C) option to change the working directory before
|
||||
executing the subsidiary program.
|
||||
|
||||
expr supports multibyte strings for all string operations.
|
||||
|
||||
** Improvements
|
||||
|
||||
@ -16968,6 +16968,25 @@ environment.
|
||||
@opindex --ignore-environment
|
||||
Start with an empty environment, ignoring the inherited environment.
|
||||
|
||||
@item -C @var{dir}
|
||||
@itemx --chdir=@var{dir}
|
||||
@opindex -C
|
||||
@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}
|
||||
|
||||
37
src/env.c
37
src/env.c
@ -38,6 +38,7 @@ 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, 'C'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{NULL, 0, NULL, 0}
|
||||
@ -63,6 +64,9 @@ 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\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
-C, --chdir=DIR change working directory to DIR\n\
|
||||
"), stdout);
|
||||
fputs (HELP_OPTION_DESCRIPTION, stdout);
|
||||
fputs (VERSION_OPTION_DESCRIPTION, stdout);
|
||||
@ -81,6 +85,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]);
|
||||
@ -91,7 +96,7 @@ main (int argc, char **argv)
|
||||
initialize_exit_failure (EXIT_CANCELED);
|
||||
atexit (close_stdout);
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "+iu:0", longopts, NULL)) != -1)
|
||||
while ((optc = getopt_long (argc, argv, "+C:iu:0", longopts, NULL)) != -1)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
@ -103,6 +108,9 @@ main (int argc, char **argv)
|
||||
case '0':
|
||||
opt_nul_terminate_output = true;
|
||||
break;
|
||||
case 'C':
|
||||
newdir = optarg;
|
||||
break;
|
||||
case_GETOPT_HELP_CHAR;
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
default:
|
||||
@ -120,7 +128,7 @@ main (int argc, char **argv)
|
||||
}
|
||||
|
||||
optind = 0; /* Force GNU getopt to re-initialize. */
|
||||
while ((optc = getopt_long (argc, argv, "+iu:0", longopts, NULL)) != -1)
|
||||
while ((optc = getopt_long (argc, argv, "+C:iu:0", longopts, NULL)) != -1)
|
||||
if (optc == 'u' && unsetenv (optarg))
|
||||
die (EXIT_CANCELED, errno, _("cannot unset %s"), quote (optarg));
|
||||
|
||||
@ -139,19 +147,34 @@ main (int argc, char **argv)
|
||||
optind++;
|
||||
}
|
||||
|
||||
/* If no program is specified, print the environment and exit. */
|
||||
if (argc <= optind)
|
||||
bool program_specified = optind < argc;
|
||||
|
||||
if (opt_nul_terminate_output && program_specified)
|
||||
{
|
||||
error (0, 0, _("cannot specify --null (-0) with command"));
|
||||
usage (EXIT_CANCELED);
|
||||
}
|
||||
|
||||
if (newdir && ! program_specified)
|
||||
{
|
||||
error (0, 0, _("must specify command with --chdir (-C)"));
|
||||
usage (EXIT_CANCELED);
|
||||
}
|
||||
|
||||
if (! program_specified)
|
||||
{
|
||||
/* Print the environment and exit. */
|
||||
char *const *e = environ;
|
||||
while (*e)
|
||||
printf ("%s%c", *e++, opt_nul_terminate_output ? '\0' : '\n');
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (opt_nul_terminate_output)
|
||||
if (newdir)
|
||||
{
|
||||
error (0, errno, _("cannot specify --null (-0) with command"));
|
||||
usage (EXIT_CANCELED);
|
||||
if (chdir (newdir) != 0)
|
||||
die (EXIT_CANCELED, errno, _("cannot change directory to %s"),
|
||||
quoteaf (newdir));
|
||||
}
|
||||
|
||||
execvp (argv[optind], &argv[optind]);
|
||||
|
||||
@ -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,17 @@ 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
|
||||
returns_ 125 env -C empty 2>out || fail=1
|
||||
printf '%s\n' \
|
||||
'env: must specify command with --chdir (-C)' \
|
||||
"Try 'env --help' for more information." > exp ||
|
||||
framework_failure_
|
||||
compare exp out || fail=1
|
||||
exp=$(cd empty && env pwd) || framework_failure_
|
||||
got=$(env --chdir=empty pwd) || fail=1
|
||||
test "$exp" = "$got" || fail=1
|
||||
|
||||
Exit $fail
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user