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

Reply via email to