From 5ef08864113505c6392158c9fac9a6cb1b3ac0e6 Mon Sep 17 00:00:00 2001 From: Pádraig Brady
Date: Tue, 3 Nov 2015 12:56:22 +0000
Subject: printf: support the %q format to quote for shell
* src/printf.c (usage): Mention the new format.
(print_formatted): Handle the quoting by calling
out to the quotearg module with "shell-escape" mode.
* doc/coreutils.texi (printf invocation): Document %q.
* tests/misc/printf-quote.sh: New test.
* tests/local.mk: Reference new test.
* NEWS: Mention the new feature.
---
NEWS | 6 +++++
doc/coreutils.texi | 10 +++++++-
src/printf.c | 20 +++++++++++++++-
tests/local.mk | 1 +
tests/misc/printf-quote.sh | 57 ++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 92 insertions(+), 2 deletions(-)
create mode 100755 tests/misc/printf-quote.sh
diff --git a/NEWS b/NEWS
index 30603e62e..38b466465 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,12 @@ GNU coreutils NEWS -*- outline -*-
base32 is added to complement the existing base64 command,
and encodes and decodes printable text as per RFC 4648.
+** New features
+
+ printf now supports the '%q' format to print arguments in a form that
+ is reusable by most shells, with non-printable characters escaped
+ with the POSIX proposed $'...' syntax.
+
** Changes in behavior
base64 no longer supports hex or oct --wrap parameters,
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 177379b38..8618a6457 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -12075,7 +12075,7 @@ one.
@item
@kindex %b
-@command{printf} has an additional directive, @samp{%b}, which prints its
+An additional directive @samp{%b}, prints its
argument string with @samp{\} escapes interpreted in the same way as in
the @var{format} string, except that octal escapes are of the form
@samp{\0@var{ooo}} where @var{ooo} is 0 to 3 octal digits. If
@@ -12083,6 +12083,14 @@ the @var{format} string, except that octal escapes are of the form
If a precision is also given, it limits the number of bytes printed
from the converted string.
+@item
+@kindex %q
+An additional directive @samp{%q}, prints its argument string
+in a format that can be reused as input by most shells.
+Non-printable characters are escaped with the POSIX proposed @samp{$''} syntax,
+and shell metacharacters are quoted appropriately.
+This is an equivalent format to @command{ls --quoting=shell-escape} output.
+
@item
Numeric arguments must be single C constants, possibly with leading
@samp{+} or @samp{-}. For example, @samp{printf %.4d -3} outputs
diff --git a/src/printf.c b/src/printf.c
index 3e68b995f..a24494631 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -41,6 +41,10 @@
%b = print an argument string, interpreting backslash escapes,
except that octal escapes are of the form \0 or \0ooo.
+ %q = print an argument string in a format that can be
+ reused as shell input. Escaped characters used the proposed
+ POSIX $'' syntax supported by most shells.
+
The 'format' argument is re-used as many times as necessary
to convert all of the given arguments.
@@ -124,7 +128,9 @@ FORMAT controls the output as in C printf. Interpreted sequences are:\n\
%% a single %\n\
%b ARGUMENT as a string with '\\' escapes interpreted,\n\
except that octal escapes are of the form \\0 or \\0NNN\n\
-\n\
+ %q ARGUMENT is printed in a format that can be reused as shell input,\n\
+ escaping non-printable characters with the proposed POSIX $'' syntax.\
+\n\n\
and all C format specifications ending with one of diouxXfeEgGcs, with\n\
ARGUMENTs converted to proper type first. Variable widths are handled.\n\
"), stdout);
@@ -506,6 +512,18 @@ print_formatted (const char *format, int argc, char **argv)
break;
}
+ if (*f == 'q')
+ {
+ if (argc > 0)
+ {
+ fputs (quotearg_style (shell_escape_quoting_style, *argv),
+ stdout);
+ ++argv;
+ --argc;
+ }
+ break;
+ }
+
memset (ok, 0, sizeof ok);
ok['a'] = ok['A'] = ok['c'] = ok['d'] = ok['e'] = ok['E'] =
ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o'] =
diff --git a/tests/local.mk b/tests/local.mk
index ee4068d64..f65f7bcc8 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -313,6 +313,7 @@ all_tests = \
tests/misc/printf-cov.pl \
tests/misc/printf-hex.sh \
tests/misc/printf-surprise.sh \
+ tests/misc/printf-quote.sh \
tests/misc/pwd-long.sh \
tests/misc/readlink-fp-loop.sh \
tests/misc/readlink-root.sh \
diff --git a/tests/misc/printf-quote.sh b/tests/misc/printf-quote.sh
new file mode 100755
index 000000000..73fc404b8
--- /dev/null
+++ b/tests/misc/printf-quote.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# tests for printf %q
+
+# Copyright (C) 2015 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see