Discussion:
unable to escape ! in autotest stdout comparison text
John Calcote
2018-05-30 01:25:56 UTC
Permalink
I'm trying to create a test using autotest that compares the stdout of my
program with a string. Unfortunately, the output of the program contains
the path of the program. As part of its output, it writes its own program
name (from argv[0]) to stdout, so I have to use ${abs_top_builddir} as part
of the comparison text - which means I need to use AT_CHECK_UNQUOTED.

Another wrench in the works is that it then also adds an exclamation mark
(!) to the end of the line, so the stdout text I'm trying to compare with
ends with ! - when I run the test, the unquoting code appears to evaluate
the ! and remove the line (bash history feature, I think - there's nothing
in the history starting with my string, so it replaces the entire string
with nothing).

I've tried escaping with backslash, I've tried quoting with single quotes,
I've tried escaping within double quotes. Nothing works. It seems the
unquoting functionality will not be tricked into allowing a special
character to be escaped.

Any ideas?

Here's my testsuite.at:

AT_INIT
AT_SETUP([tg1])
AT_CHECK_UNQUOTED(["${abs_top_builddir}/src/prog"],,
[Hello from ${abs_top_builddir}/src/prog!])
AT_CLEANUP

I'm open to using AT_CHECK also - but I haven't figured out a good way to
access my program without using the shell variables defined in atconfig.

Thanks in advance!
John
Nick Bowler
2018-05-30 01:34:32 UTC
Permalink
Post by John Calcote
I'm trying to create a test using autotest that compares the stdout of my
program with a string. Unfortunately, the output of the program contains
the path of the program. As part of its output, it writes its own program
name (from argv[0]) to stdout, so I have to use ${abs_top_builddir} as part
of the comparison text - which means I need to use AT_CHECK_UNQUOTED.
[snip problems with unwanted shell expansion]
Post by John Calcote
Any ideas?
There might be ways to avoid your problems with AC_CHECK_UNQUOTED, but
it is probably simplest to just sidestep the issue. In your test group,
you can write the expected standard output to a file named expout. You
can generate this in any manner you would like (likely with some shell
commands).

Then, instead of specifying the expected output directly in AT_CHECK,
you put 'expout' for the standard output:

AT_CHECK([blah],,[expout])

which will compare the standard output against the contents of the file.
Post by John Calcote
AT_INIT
AT_SETUP([tg1])
AT_CHECK_UNQUOTED(["${abs_top_builddir}/src/prog"],,
[Hello from ${abs_top_builddir}/src/prog!])
AT_CLEANUP
So, we can do (totally untested)

AT_INIT
AT_SETUP([tg1])
printf 'Hello from %s/src/prog!\n' "$abs_top_builddir" >expout
AT_CHECK(["$abs_top_builddir/src/prog"],,[expout])
AT_CLEANUP

Hope that helps,
Nick
John Calcote
2018-05-30 01:47:01 UTC
Permalink
Post by Nick Bowler
Post by John Calcote
I'm trying to create a test using autotest that compares the stdout of my
So, we can do (totally untested)
AT_INIT
AT_SETUP([tg1])
printf 'Hello from %s/src/prog!\n' "$abs_top_builddir" >expout
AT_CHECK(["$abs_top_builddir/src/prog"],,[expout])
AT_CLEANUP
Nick, your "totally untested" code works perfectly!

I'd actually thought of using expout, but was hoping for a more compact
solution. I think I've exhausted all the ways I've ever heard of
escaping/emasculating a bang in a command line. Was sort of hoping to find
some shell guru out there. The thing is, though, it's one of those
situations where the expansion functionality in autotest is just a little
less functional than the shell itself.

Thanks!
John
Eric Blake
2018-05-30 02:10:49 UTC
Permalink
Post by John Calcote
I'm trying to create a test using autotest that compares the stdout of my
program with a string. Unfortunately, the output of the program contains
the path of the program. As part of its output, it writes its own program
name (from argv[0]) to stdout, so I have to use ${abs_top_builddir} as part
of the comparison text - which means I need to use AT_CHECK_UNQUOTED.
Another wrench in the works is that it then also adds an exclamation mark
(!) to the end of the line, so the stdout text I'm trying to compare with
ends with ! - when I run the test, the unquoting code appears to evaluate
the ! and remove the line (bash history feature, I think - there's nothing
in the history starting with my string, so it replaces the entire string
with nothing).
Yeah, bash's handling of ! can be quite a misfeature when you don't want
it to happen during scripting. But I thought it was disabled by default
in POSIX mode, which is what autotest scripts should be selecting, so
are you sure that history expansion is happening?
Post by John Calcote
I've tried escaping with backslash, I've tried quoting with single quotes,
I've tried escaping within double quotes. Nothing works. It seems the
unquoting functionality will not be tricked into allowing a special
character to be escaped.
Any ideas?
AT_INIT
AT_SETUP([tg1])
AT_CHECK_UNQUOTED(["${abs_top_builddir}/src/prog"],,
[Hello from ${abs_top_builddir}/src/prog!])
AT_CLEANUP
First, are you sure you don't want a trailing newline? That is, did
src/prog output "!" as it's last character, or "\n" after the "!"? (The
placement of the ] in AT_CHECK[_UNQUOTED] matters).

I couldn't quickly reproduce the mangling of ! even though bash is my
shell and my /bin/sh, but I did reproduce failure using that
testsuite.at as you gave plus a minimal src/prog, configure.ac, and
Makefile.am for compiling and running the testsuite, due to the
difference in newlines. Once I fixed that, the test ran successfully.
To double-check, look at the generated testsuite, and show the code that
it is creating just before AT_STOP_1 (here's what I see with autoconf 2.69):

...
$as_echo "$at_srcdir/testsuite.at:3: \"\${abs_top_builddir}/src/prog\""
at_fn_check_prepare_notrace 'a ${...} parameter expansion' "testsuite.at:3"
( $at_check_trace; "${abs_top_builddir}/src/prog"
) >>"$at_stdout" 2>>"$at_stderr" 5>&-
at_status=$? at_failed=false
$at_check_filter
at_fn_diff_devnull "$at_stderr" || at_failed=:
echo >>"$at_stdout"; $as_echo "Hello from ${abs_top_builddir}/src/prog!
" | \
$at_diff - "$at_stdout" || at_failed=:
...

And $as_echo doesn't appear to be mangling ! for me, as long as I have
the right trailing newline.

But since the output is variable, perhaps the easiest thing is to
post-process the output prior to comparing it to fixed text, as in:

AT_INIT
AT_SETUP([tg1])
AT_CHECK_UNQUOTED(["${abs_top_builddir}/src/prog" |
sed "s|${abs_top_builddir}|DIR|"],,
[Hello from DIR/src/prog!
])
AT_CLEANUP
Post by John Calcote
I'm open to using AT_CHECK also - but I haven't figured out a good way to
access my program without using the shell variables defined in atconfig.
My approach works with both AT_CHECK and AT_CHECK_UNQUOTED, as there is
no longer anything variable in the expected output. In fact, since bash
changes argv[0] into the absolute path when a PATH lookup was performed,
this also works:

AT_CHECK([PATH=$abs_top_builddir/src:$PATH; prog | sed ...] ...
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org
John Calcote
2018-05-30 03:19:43 UTC
Permalink
Post by Eric Blake
Post by John Calcote
I'm trying to create a test using autotest that compares the stdout of my
program with a string. Unfortunately, the output of the program contains
the path of the program. As part of its output, it writes its own program
name (from argv[0]) to stdout, so I have to use ${abs_top_builddir} as part
of the comparison text - which means I need to use AT_CHECK_UNQUOTED.
Yeah, bash's handling of ! can be quite a misfeature when you don't want
it to happen during scripting. But I thought it was disabled by default in
POSIX mode, which is what autotest scripts should be selecting, so are you
sure that history expansion is happening?
...
Post by Eric Blake
First, are you sure you don't want a trailing newline? That is, did
src/prog output "!" as it's last character, or "\n" after the "!"? (The
placement of the ] in AT_CHECK[_UNQUOTED] matters).
I did not realize autotest was using POSIX mode - that makes it a little
harder to explain. All I know for sure is that the output in testsuite.log
showed an empty string for the comparison text when I don't use a newline
after the bang. On the other hand, when I do use a newline after the bang,
as you suggested, it works perfectly. I always think I'll look so smart by
figuring it out and explaining the situation in posts like this, then I
find that my original assumption was nowhere near the truth. :)

More research is in order.

Thanks Eric.
Gavin Smith
2018-05-31 14:15:02 UTC
Permalink
Post by John Calcote
I've tried escaping with backslash, I've tried quoting with single quotes,
I've tried escaping within double quotes. Nothing works. It seems the
unquoting functionality will not be tricked into allowing a special
character to be escaped.
Any ideas?
I don't know if it works in your situation but another way of
"escaping" a special character is to assign it to a shell variable,
e.g. do

bang='!'

somewhere and later refer to ${bang}. This may work if variable
expansion takes place at a later stage than when the special
characters in question are processed.

Loading...