On 11/28/18 10:00 AM, Bruno Haible wrote:
Hi Ben,
This patch silences some warnings from Shellcheck, mostly about using
POSIX $(..) command substitutions instead of old backtick
substitutions.
The script starts with '#!/bin/sh'. /bin/sh on IRIX does not support
$(...). But I think no GNU maintainer is using IRIX on their development
machine. Therefore it's fine with me.
- conf=`sed 's/#.*$//;/^$/d' "$conffile" | tr "\015$nl" ' '`
+ conf=$(sed 's/#.*$//;/^$/d' "$conffile" | tr "\\015$nl" ' ')
Is the interpretation of backslashes inside $(...) different than
inside `...`?
Yes. Inside ``, \ is an escape for $, `, and \; \ in front of anything
else the \ is preserved literally, but may be subject to further
interpretation according to the contents within ``. Inside $(), the
normal shell grammar applies, and the closing ) is determined by whether
you can parse the contents as a shell script. As a demonstration (using
printf, since using echo has its own problems when an echo
implementation also does backslash interpolation):
$ printf %s\\n `printf %s "\\\\"`
\
$ printf %s\\n $(printf %s "\\\\")
\\
Within ``, there are two \\ pairs flattened to \ before the shell parses
the command to substitute; but parsing "\\" for the inner printf results
in a single \ output. Within $(), there is no flattening before the
shell parses the command to substitute, and parsing "\\\\" for the inner
printf results in a doubled \ output.
Or:
$ printf %s\\n `printf %s "\\\"`
\
Well-formed - there is one \\ pair, flattened to \, while the third \ is
followed by " so it is output literally, which means the inner parser
sees "\\" which is well-formed, and results in a single \ output via printf.
$ printf %s\\n $(printf %s "\\\")
>
Here, the shell follows its normal parsing rules - it is looking for a
closing ", because within "\\\"...., the first \\ pair is a single
quoted \, the next \" is a quoted ", the ) and newline also part of the
double-quoted string, and so on. Until you supply a closing " and then
another ) to end the $() construct, the shell is waiting for more input
to parse. Thus, conversion of `` to $() MUST be aware of any changed
handling of \ present in the command substitution.
Or is this an independent fix?
Hard to say. Note that:
printf %s "\015"
printf %s "\\015"
both output five bytes (single backslash, three digits, and a newline) -
that's because in "", \ followed by an unknown character still outputs
the \ verbatim. So the tr process is not seeing any change to its
arguments - `"\015"` and $("\015") are the same as `"\\\\015"` and
$("\\015") (the former two relying on the character after \ not being
special and therefore the \ being used literally, the latter two being
fully escaped to ensure that a single literal \ results). But switching
between non-special form and fully-escaped form is odd, and should be
done independently if at all - in general, the conversion from `` to $()
should only ever remove \ that were special to `` but not needed for
$(), and not ever need to add \.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org