Pádraig Brady <[email protected]> writes: > On 06/08/2026 05:54, Collin Funk wrote: >> Pádraig Brady <[email protected]> writes: > >>> Yes, it makes sense to quote even when redirecting >>> (unless QUOTE_STYLE=literal) as we were discussing at: >>> https://github.com/coreutils/coreutils/issues/324 >>> >>> One small worry is breaking usage like: >>> foo=$(printenv foo) or popen("printenv foo"). >>> But that's not a practical concern as it's much more >>> natural to access particular env vars directly. >>> I did audit the following just in case: >>> https://codesearch.debian.net/search?q=printenv.*\|.*(cut|sed)&literal=0 >>> but noticed no problematic usage. >>> In fact quoting newlines in env var values would >>> make the found usages more robust. >> In the more general cases (ignoring many that are obvious tests), I >> have >> found it is mostly stuff like this: >> $ printenv LC_ALL >> [...] >> That one should obviously not be defined in a way that needs quoted. >> I have also seen stuff like this: >> $ printenv | grep '^SSH_' >> [...] >> That one should probably not ever have the need to be quoted, but I >> guess it is possible. In any case, that one would be buggy if someone >> defines an environment variable with "SSH_" following a newline. > Thinking a bit more about this, it might be safer to > limit the single variable case to only quote to tty by default. > > For example to support usage like: > > user_color=$(run0 --user="$user" printenv user_color) > > E.g. if $user_color contained ANSI escapes we'd want them unquoted. > Note the trailing newline would be auto stripped in the above, > allowing such usage.
I think I agree. It feels a little weird to behave differently based on the number of arguments, but I think that case warrants it. I've attached an incomplete patch to do that. I'll probably adjust NEWS and the documentation a bit. One thing I'm unsure about is whether a test for tty output should be added to the same test or in misc/tty-quoting.sh. It seems like the ones there are tailored to a single argument, where we should test both single argument and multiple arguments in this case, I think. I don't want that look to be *too* full of edge cases such that it gets difficult to understand. WDYT? Collin
>From e120ace06d06d22b67eea913281eec3fe99f66bb Mon Sep 17 00:00:00 2001 Message-ID: <e120ace06d06d22b67eea913281eec3fe99f66bb.1788033098.git.collin.fu...@gmail.com> From: Collin Funk <[email protected]> Date: Sat, 29 Aug 2026 12:49:06 -0700 Subject: [PATCH] printenv: don't quote output with no terminal and a single argument * src/printenv.c (main): Make sure quoting is disabled when we have a single argument and standard output is not a terminal. * tests/misc/printenv.sh: Adjust single argument test cases. Add multiple argument test cases. --- src/printenv.c | 3 +++ tests/misc/printenv.sh | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/printenv.c b/src/printenv.c index 540f56334..8bfb7d7bb 100644 --- a/src/printenv.c +++ b/src/printenv.c @@ -144,6 +144,9 @@ main (int argc, char **argv) { bool matched = false; + quote_output = (quote_output + && (1 < argc - optind || isatty (STDOUT_FILENO))); + /* 'printenv a=b' is silent, even if 'a=b=c' is in environ. */ if (strchr (argv[i], '=')) continue; diff --git a/tests/misc/printenv.sh b/tests/misc/printenv.sh index 8ec228a6a..47f37b5c5 100755 --- a/tests/misc/printenv.sh +++ b/tests/misc/printenv.sh @@ -84,17 +84,24 @@ compare /dev/null out || fail=1 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 || framework_failure_ cat <<\EOF >exp-args-shell || framework_failure_ 'c d' +'c d' EOF -tr "'" '"' <exp-noargs-shell >exp-noargs-c || framework_failure_ -tr "'" '"' <exp-args-shell >exp-args-c || framework_failure_ +for t in noargs arg args; do + tr "'" '"' <exp-$t-shell >exp-$t-c || framework_failure_ +done for qs in literal shell c; do env -i PATH="$PATH" QUOTING_STYLE=$qs 'a b'='c d' \ printenv >out-t 2>err || fail=1 @@ -104,6 +111,10 @@ for qs in literal shell c; do 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 /dev/null err || fail=1 done -- 2.55.0
