From: Pádraig Brady
Date: Fri, 31 Jul 2026 16:35:52 +0000 (+0100)
Subject: du: quote problematic names on tty
X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d18b73bb688adadee5ed834c65e0a20e134ddf88;p=thirdparty%2Fcoreutils.git
du: quote problematic names on tty
* doc/coreutils.texi (readlink invocation): Mention $QUOTING_STYLE
is significant.
* src/du.c (main): Quote output when appropriate.
* tests/du/basic.sh: Add a test case.
* NEWS: Mention the improvement.
---
diff --git a/NEWS b/NEWS
index 2db6c99ae0..3a7b175e30 100644
--- a/NEWS
+++ b/NEWS
@@ -84,9 +84,9 @@ GNU coreutils NEWS -*- outline -*-
'install -C' will now avoid updating file metadata when the destination
already has the appropriate ownership and permissions.
- 'basename', 'readlink', and 'realpath' now quote output in shell-escape style
- when standard output is a terminal. The QUOTING_STYLE environment variable
- can be used to adjust or disable the quoting.
+ 'basename', 'du', 'readlink', and 'realpath' now quote output in shell-escape
+ style when standard output is a terminal. The QUOTING_STYLE environment
+ variable can be used to adjust or disable the quoting.
'ls -m' now quotes files names containing commas when appropriate,
so users can better distinguish separating commas.
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index b675b6345a..441b80c3c5 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -12436,6 +12436,11 @@ the argument being processed is on.
@end table
+When standard output is a terminal, file names are quoted using
+the @samp{shell-escape} style. The environment variable
+@env{QUOTING_STYLE} can select the quoting style. Valid quoting styles are:
+@quotingStyles
+
Since @command{du} relies on information reported by the operating
system, its output might not reflect the space consumed in the
underlying devices. For example;
diff --git a/src/du.c b/src/du.c
index eefb24f05a..7c9c486f1c 100644
--- a/src/du.c
+++ b/src/du.c
@@ -26,7 +26,7 @@
#include
#include
#include
-#include "argmatch.h"
+#include "argmatch.h" /* argmatch($QUOTING_STYLE). */
#include "system.h"
#include "argv-iter.h"
#include "assure.h"
@@ -135,6 +135,9 @@ static bool hash_all;
/* If true, output the NUL byte instead of a newline at the end of each line. */
static bool opt_nul_terminate_output = false;
+/* If true, quote output pathnames according to the selected quoting style. */
+static bool quote_output;
+
/* If true, print a grand total at the end. */
static bool print_grand_total = false;
@@ -445,10 +448,11 @@ print_only_size (uintmax_t n_bytes)
stdout);
}
-/* Print size (and optionally time) indicated by *PDUI, followed by STRING. */
+/* Print size (and optionally time) indicated by *PDUI, followed by STRING,
+ quoting STRING if QUOTE is true. */
static void
-print_size (const struct duinfo *pdui, char const *string)
+print_size (const struct duinfo *pdui, char const *string, bool quote)
{
print_only_size (opt_inodes
? pdui->inodes
@@ -466,7 +470,7 @@ print_size (const struct duinfo *pdui, char const *string)
}
}
putchar ('\t');
- fputs (string, stdout);
+ fputs (quote ? quoteN (string) : string, stdout);
putchar (opt_nul_terminate_output ? '\0' : '\n');
if (fflush (stdout) < 0)
write_error ();
@@ -718,7 +722,7 @@ process_file (FTS *fts, FTSENT *ent)
if (opt_threshold < 0
? v <= -opt_threshold
: v >= opt_threshold)
- print_size (&dui_to_print, file);
+ print_size (&dui_to_print, file, quote_output);
}
return ok;
@@ -983,6 +987,18 @@ main (int argc, char **argv)
if (!ok)
usage (EXIT_FAILURE);
+ if (!opt_nul_terminate_output && isatty (STDOUT_FILENO))
+ {
+ int qs = getenv_quoting_style ();
+ if (qs < 0)
+ qs = shell_escape_quoting_style;
+ if (qs != literal_quoting_style)
+ {
+ set_quoting_style (NULL, qs);
+ quote_output = true;
+ }
+ }
+
if (opt_all && opt_summarize_only)
{
error (0, 0, _("cannot both summarize and show all entries"));
@@ -1192,7 +1208,7 @@ main (int argc, char **argv)
error (EXIT_FAILURE, 0, _("error reading %s"), quoteaf (files_from));
if (print_grand_total)
- print_size (&tot_dui, _("total"));
+ print_size (&tot_dui, _("total"), false);
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/tests/du/basic.sh b/tests/du/basic.sh
index 3bf74f712b..45567f71d7 100755
--- a/tests/du/basic.sh
+++ b/tests/du/basic.sh
@@ -28,6 +28,21 @@ printf '%*s' 257 make-sure-the-file-is-non-empty > a/b/F || framework_failure_
printf %4096s x > d/1
cp d/1 d/sub/2
+# QUOTING_STYLE does not affect redirected output.
+touch 'q name' || framework_failure_
+printf '0\tq name\n' > exp || framework_failure_
+for style in literal shell-always invalid; do
+ QUOTING_STYLE="$style" du -b 'q name' > out 2> err || fail=1
+ compare exp out || fail=1
+ compare /dev/null err || fail=1
+done
+
+# --null disables quoting, and does not inspect QUOTING_STYLE.
+QUOTING_STYLE=invalid du -0b 'q name' > out 2> err || fail=1
+printf '0\tq name\0' > exp || framework_failure_
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
B=$(stat --format=%B a/b/F)