From 410f48719c378c1812ecd26d5a80a5f1144e2222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1draig=20Brady?= Date: Tue, 15 Sep 2026 20:26:28 +0100 Subject: [PATCH 1/2] env,printenv: only quote when outputting to terminals To support albeit non-robust but existing use cases like: env | grep SPARK_JAVA_OPT_ | sort -t_ -k4 -n | sed 's/[^=]*=\(.*\)/\1/g' > java_opts.txt readarray -t SPARK_EXECUTOR_JAVA_OPTS < java_opts.txt ... CMD=("${JAVA_HOME}/bin/java" "${SPARK_EXECUTOR_JAVA_OPTS[@]}" ...) * src/env.c (main): Restrict quoting to terminals. * src/printenv.c (main): Likewise. * tests/env/env.sh: Adjust accordingly. * tests/misc/printenv.sh: Likewise. * doc/coreutils.texi: Likewise. * NEWS: Mention the change in behavior. Link: https://github.com/coreutils/coreutils/issues/355 --- NEWS | 6 ++++++ doc/coreutils.texi | 16 ++++++---------- src/env.c | 2 +- src/printenv.c | 2 +- tests/env/env.sh | 31 +++++++------------------------ tests/misc/printenv.sh | 40 ++++------------------------------------ 6 files changed, 25 insertions(+), 72 deletions(-) diff --git a/NEWS b/NEWS index b59f543ec..1b0618576 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,12 @@ GNU coreutils NEWS -*- outline -*- * Noteworthy changes in release ?.? (????-??-??) [?] +** Changes in behavior + + 'env' and 'printenv' now quote printed environment variables only when + outputting to a terminal. The previous release enabled this for all + outputs by default, requiring setting QUOTING_STYLE=literal to disable. + * Noteworthy changes in release 9.12 (2026-09-14) [stable] diff --git a/doc/coreutils.texi b/doc/coreutils.texi index b769e64c1..9d7888511 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -15519,13 +15519,9 @@ The program accepts the following option. Also see @ref{Common options}. @end table -If no @var{variable}s are specified, @command{printenv} quotes +If standard output is a terminal @command{printenv} quotes environment variables and their values using the @samp{shell-escape} -style. If @var{variable}s are specified, @command{printenv} only quotes -their values using the @samp{shell-escape} style if standard output is a -terminal. - -The environment variable @env{QUOTING_STYLE} +style by default. The environment variable @env{QUOTING_STYLE} specifies the quoting style. Valid quoting styles are: @quotingStyles @@ -17497,10 +17493,10 @@ If no command name is specified following the environment specifications, the resulting environment is printed. This is like specifying the @command{printenv} program. -The printed environment variables and their values are quoted using the -@samp{shell-escape} style. The environment variable -@env{QUOTING_STYLE} specifies the quoting style. Valid quoting styles -are: +If standard output is a terminal, the printed environment variables +and their values are quoted using the @samp{shell-escape} style by default. +The environment variable @env{QUOTING_STYLE} specifies the quoting style. +Valid quoting styles are: @quotingStyles For some examples, suppose the environment passed to @command{env} diff --git a/src/env.c b/src/env.c index e646cba96..8fff89e72 100644 --- a/src/env.c +++ b/src/env.c @@ -1113,7 +1113,7 @@ main (int argc, char **argv) /* Get the value from QUOTING_STYLE before unsetting environment variables. */ - if (!opt_nul_terminate_output) + if (!opt_nul_terminate_output && isatty (STDOUT_FILENO)) { int qs = getenv_quoting_style (); if (qs < 0) diff --git a/src/printenv.c b/src/printenv.c index dba87f373..00ca29f55 100644 --- a/src/printenv.c +++ b/src/printenv.c @@ -113,7 +113,7 @@ main (int argc, char **argv) bool quote_output = false; idx_t const n_args = argc - optind; - if (!opt_nul_terminate_output && (n_args <= 0 || isatty (STDOUT_FILENO))) + if (!opt_nul_terminate_output && isatty (STDOUT_FILENO)) { int qs = getenv_quoting_style (); if (qs < 0) diff --git a/tests/env/env.sh b/tests/env/env.sh index be822e346..8853e0163 100755 --- a/tests/env/env.sh +++ b/tests/env/env.sh @@ -91,18 +91,14 @@ EOF compare exp out || fail=1 # env shouldn't care what encoding name or value is -cat <<\EOF >exp || framework_failure_ -NON_UTF8_TEST=''$'\240' -EOF +printf 'NON_UTF8_TEST=\240\n' > exp || framework_failure_ env $(printf 'NON_UTF8_TEST=\240') env > all || fail=1 grep '^NON_UTF8_TEST' all | LC_ALL=C sort > out || framework_failure_ compare exp out || fail=1 -cat <<\EOF >exp || framework_failure_ -'NON_UTF8_TEST'$'\240'=1 -EOF +printf 'NON_UTF8_TEST\240=1\n' > exp || framework_failure_ env $(printf 'NON_UTF8_TEST\240=1') env > all || fail=1 -grep "^'NON_UTF8_TEST" all | LC_ALL=C sort > out || framework_failure_ +grep "^NON_UTF8_TEST" all | LC_ALL=C sort > out || framework_failure_ compare exp out || fail=1 # PATH modifications affect exec. @@ -193,29 +189,16 @@ EOF compare err_exp err || fail=1 done -# QUOTING_STYLE affects redirected output. -cat <<\EOF >exp-noargs-literal || framework_failure_ -a b=c d -EOF -cat <<\EOF >exp-noargs-shell || framework_failure_ -'a b'='c d' -EOF -tr "'" '"' exp-noargs-c || framework_failure_ -for qs in literal shell c; do +# QUOTING_STYLE does not affect redirected output. +printf '%s\n' 'a b=c d' > exp || framework_failure_ +for qs in literal shell-always invalid; do env -i PATH="$PATH" QUOTING_STYLE=$qs 'a b'='c d' \ env >out-t 2>err || fail=1 grep -vE '^["'"'"']?'\ '(__CF_USER_TEXT_ENCODING|QUOTING_STYLE|(LD_ORIGIN_)?PATH)["'"'"']?=' \ out-t >out || framework_failure_ - compare exp-noargs-$qs out || fail=1 + compare exp out || fail=1 compare /dev/null err || fail=1 done -# Check the behavior with an invalid value for QUOTING_STYLE. -printf 'env: ignoring invalid value of environment variable %s\n' \ - "QUOTING_STYLE: 'invalid'" >exp || framework_failure_ -env QUOTING_STYLE=invalid env >out 2>err || fail=1 -grep '^QUOTING_STYLE=invalid$' out || fail=1 -compare exp err || fail=1 - Exit $fail diff --git a/tests/misc/printenv.sh b/tests/misc/printenv.sh index b8c3696c4..33ad6cc51 100755 --- a/tests/misc/printenv.sh +++ b/tests/misc/printenv.sh @@ -80,48 +80,16 @@ compare exp out || fail=1 returns_ 1 env a=b=c printenv a=b > out || fail=1 compare /dev/null out || fail=1 -# QUOTING_STYLE affects redirected output. -cat <<\EOF >exp-noargs-literal || framework_failure_ -a b=c d -EOF -cat <<\EOF >exp-arg-literal || framework_failure_ -c d -EOF -cat <<\EOF >exp-args-literal || framework_failure_ -c d -c d -EOF -cat <<\EOF >exp-noargs-shell || framework_failure_ -'a b'='c d' -EOF -cp exp-arg-literal exp-arg-shell && -cp exp-args-literal exp-args-shell || framework_failure_ -for t in noargs arg args; do - tr "'" '"' exp-$t-c || framework_failure_ -done -for qs in literal shell c; do +# QUOTING_STYLE does not affect redirected output. +printf '%s\n' 'a b=c d' > exp || framework_failure_ +for qs in literal shell-always invalid; do env -i PATH="$PATH" QUOTING_STYLE=$qs 'a b'='c d' \ printenv >out-t 2>err || fail=1 grep -vE '^["'"'"']?'\ '(__CF_USER_TEXT_ENCODING|QUOTING_STYLE|(LD_ORIGIN_)?PATH)["'"'"']?=' \ out-t >out || framework_failure_ - compare exp-noargs-$qs out || fail=1 - compare /dev/null err || fail=1 - env -i PATH="$PATH" QUOTING_STYLE=$qs 'a b'='c d' \ - printenv 'a b' >out 2>err || fail=1 - compare exp-arg-$qs out || fail=1 - compare /dev/null err || fail=1 - env -i PATH="$PATH" QUOTING_STYLE=$qs 'a b'='c d' \ - printenv 'a b' 'a b' >out 2>err || fail=1 - compare exp-args-$qs out || fail=1 + compare exp out || fail=1 compare /dev/null err || fail=1 done -# Check the behavior with an invalid value for QUOTING_STYLE. -printf 'printenv: ignoring invalid value of environment variable %s\n' \ - "QUOTING_STYLE: 'invalid'" >exp || framework_failure_ -env QUOTING_STYLE=invalid printenv >out 2>err || fail=1 -grep '^QUOTING_STYLE=invalid$' out || fail=1 -compare exp err || fail=1 - Exit $fail -- 2.55.0