[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Issues with history substitution and its documentation

From: Chet Ramey
Subject: Re: Issues with history substitution and its documentation
Date: Mon, 18 Nov 2019 14:55:47 -0500
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Thunderbird/68.2.2

On 11/6/19 10:21 AM, Jim Monte wrote:
Another documentation issue for :s, and a bug, or two bugs, although it
seems to be one of each. Instead of "Any delimiter may be used in place of
‘/’.", it should be clarified that any character may be used in place of
'/' as a delimiter, although if '&' is used, it looses its special property
of being the value of old when it appears in new and if '\' is used, it
looses is ability to escape '&'.

It doesn't. I think it would be clearer after an explanation of how the
history expansion code parses substitutions and how backslashes act as
escape characters during scanning. The principle to remember up front is
that backslash can act as an escape character, but not in all contexts,
and it is removed for the next stage of history expansion if it is used
as an escape character.

However, there is still an issue with an
escape being lost in some cases.

[root@localhost ~]# echo a b c
a b c
[root@localhost ~]# echo "!:s&b&\\\&&&"
echo "echo a \& c&"                              ******************* one

This is exactly what csh does. Here's why.

The history code notes that the substitution delimiter is `&', so it has
to scan forward for the separating and closing delimiters. The separating
one after the lhs is easy. To find the closing delimiter, the backslash
escapes one `&', the second `&' terminates the history substitution, and
the third is held until later. The backslash escaping the `&' is removed.
The backslash doesn't escape itself when scanning for the ending delimiter,
so the replacement string is `\\&'.

That replacement string gets post-processed for possible & interpolation,
so it gets rescanned. During this rescanning, the backslash escapes only
the `&', and not itself, so the backslash escapes the `&' and is removed.
The final replacement string is '\&', and that gets substituted for `b'
in the original event string.

The final `&' doesn't participate in the history expansion, so it's just
appended to the result.

[root@localhost ~]# echo a b c
a b c
[root@localhost ~]# echo "!:s/b/\\\&&/"
echo "echo a \\&b c"                             *******************
echo a \&b c

Right. You don't have to consume one backslash while scanning for the
ending delimiter.

[root@localhost ~]# echo a b c
a b c
[root@localhost ~]# echo "!:szbz\\\&&z"
echo "echo a \\&b c"                             *******************
echo a \&b c

This is the same example.

[root@localhost ~]# echo a b c
a b c
[root@localhost ~]# echo "!:s\b\\\\&&\"
echo "echo a  c\\&&\"
echo a  c\&&"

[root@localhost ~]# echo a b c
a b c
[root@localhost ~]# echo "!:s\b\z\&&y\"
echo "echo a z c&&y\"
echo a z c&&y"

You should be able to work these out given the previous examples.


``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    address@hidden    http://tiswww.cwru.edu/~chet/

reply via email to

[Prev in Thread] Current Thread [Next in Thread]