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 . + +prog='env printf' + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ printf + +# Equivalent output to ls --quoting=shell-escape +env printf '%q\n' '' "'" a 'a b' '~a' 'a~' "$(env printf %b 'a\r')" > out +cat <<\EOF > exp || framework_failure_ +'' +''\''' +a +'a b' +'~a' +a~ +'a'$'\r' +EOF +compare exp out || fail=1 + +unset LC_ALL +f=$LOCALE_FR_UTF8 +: ${LOCALE_FR_UTF8=none} +if test "$LOCALE_FR_UTF8" != "none"; then + ( + #printable multi-byte + LC_ALL=$f env printf '%q\n' 'áḃç' > out + #non-printable multi-byte + LC_ALL=$f env printf '%q\n' "$(LC_ALL=$f env printf '\u0378')" >> out + #printable multi-byte in C locale + LC_ALL=C env printf '%q\n' 'áḃç' >> out + ) + cat <<\EOF > exp || framework_failure_ +áḃç +''$'\315\270' +''$'\303\241\341\270\203\303\247' +EOF + compare exp out || fail=1 +fi + +Exit $fail -- cgit v1.2.3-54-g00ecf