* doc/coreutils.texi (terminalQuoted): New macro.
(readlink invocation, basename invocation, dirname invocation): Use it.
* src/dirname.c (quote_output): New variable.
(main): Quote output when appropriate.
* src/system.h (quoteN_mem): New macro.
* tests/misc/dirname.pl: Add test cases based on the ones added for
basename in commit
e897dfd02 (basename: quote problematic names on tty,
2026-07-30). Copy some logic from tests/misc/basename.pl to test the -z
option.
* tests/misc/tty-quoting.sh: Also test dirname.
* NEWS: Mention the improvement.
'install -C' will now avoid updating file metadata when the destination
already has the appropriate ownership and permissions.
- '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.
+ 'basename', 'dirname', '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.
@end table
+@c This is also used by basename and dirname.
+@macro terminalQuoted
When standard output is a terminal, output is quoted using the
@samp{shell-escape} style. The environment variable
-@env{QUOTING_STYLE} can select the quoting style. Valid quoting styles are:
+@env{QUOTING_STYLE} specifies the quoting style. Valid quoting styles
+are:
@quotingStyles
+@end macro
+@terminalQuoted
The @command{readlink} utility first appeared in OpenBSD 2.1.
@end table
-When standard output is a terminal, output is quoted using the
-@samp{shell-escape} style. The environment variable
-@env{QUOTING_STYLE} specifies the quoting style. Valid quoting styles are:
-@quotingStyles
+@terminalQuoted
@exitstatus
@end table
+@terminalQuoted
+
@exitstatus
Examples:
#include <stdio.h>
#include <sys/types.h>
+#include "argmatch.h" /* argmatch($QUOTING_STYLE). */
#include "system.h"
/* The official name of this program (e.g., no 'g' prefix). */
proper_name ("David MacKenzie"), \
proper_name ("Jim Meyering")
+static bool quote_output;
+
static struct option const longopts[] =
{
{"zero", no_argument, NULL, 'z'},
usage (EXIT_FAILURE);
}
+
+ if (!use_nuls && 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;
+ }
+ }
+
for (; optind < argc; optind++)
{
char const *result = argv[optind];
result = ˙
len = 1;
}
-
+ if (quote_output)
+ {
+ result = quoteN_mem (result, len);
+ len = strlen (result);
+ }
fwrite (result, 1, len, stdout);
putchar (use_nuls ? '\0' :'\n');
}
/* Equivalent to quotearg(), but explicit to avoid syntax checks. */
#define quoteN(x) quotearg_style (get_quoting_style (NULL), x)
+#define quoteN_mem(x, size) \
+ quotearg_style_mem (get_quoting_style (NULL), x, size)
#ifdef ARGMATCH
/* Return the quoting style specified by the environment variable
['l', qw(///a//b/), {OUT => '///a'}],
['m', qw(''), {OUT => '.'}],
['n', qw(a/b c/d), {OUT => "a\nc"}],
+
+ # QUOTING_STYLE does not affect redirected output.
+ ['q-lit', q{'q name/f'}, {ENV => 'QUOTING_STYLE=literal'},
+ {OUT => 'q name'}],
+ ['q-shell', q{'q name/f'}, {ENV => 'QUOTING_STYLE=shell-always'},
+ {OUT => 'q name'}],
+ ['q-invalid', q{'q name/f'}, {ENV => 'QUOTING_STYLE=invalid'},
+ {OUT => 'q name'}],
+
+ ['z-quote', q{-z 'q name/f'}, {ENV => 'QUOTING_STYLE=invalid'},
+ {OUT => "q name\0"}],
);
# Append a newline to end of each expected 'OUT' string.
+# Skip -z tests, i.e., those whose 'OUT' string has a trailing '\0'.
my $t;
foreach $t (@Tests)
{
foreach $e (@$t)
{
$e->{OUT} = "$e->{OUT}\n"
- if ref $e eq 'HASH' and exists $e->{OUT};
+ if ref $e eq 'HASH' and exists $e->{OUT}
+ and not $e->{OUT} =~ /\0$/;
}
}
# along with this program. If not, see <https://www.gnu.org/licenses/>.
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
-print_ver_ basename du ls readlink realpath printf test
+print_ver_ basename dirname du ls readlink realpath printf test
require_strace_ ioctl
touch 'b ar' || framework_failure_
run_tty_ env printf foo >printf.t &&
skip_ 'libc buffering induced a tty probe'
-for cmd in basename du 'ls -w0' readlink 'realpath --relative-to=.'; do
+for cmd in basename du dirname 'ls -w0' readlink 'realpath --relative-to=.'; do
test "$cmd" = 'du' && field=2 || field=1
+ test "$cmd" = 'dirname' && file='f oo/.' || file='f oo'
- run_tty_ $cmd 'f oo' >quoted.t || fail=1
+ run_tty_ $cmd "$file" >quoted.t || fail=1
cut -f$field- quoted.t >quoted || framework_failure_
# Note ls theoretically doesn't need isatty() for a specified QUOTING_STYLE
# but it does need it to determine appropriate output format.
- QUOTING_STYLE=literal run_tty_ $cmd 'f oo' >unquoted.t || fail=1
+ QUOTING_STYLE=literal run_tty_ $cmd "$file" >unquoted.t || fail=1
cut -f$field- unquoted.t >unquoted || framework_failure_
env printf '%q\n' "$(cat unquoted)" >printf_quoted || framework_failure_