virsh: Elide backslash-newline in batch mode

The previous patch made it possible to split multiple commands by
adding newline, but not to split a long single command. The sequence
backslash-newline was being used as if it were a quoted newline
character, rather than completely elided the way the shell does.

Again, add more tests, although this time it seems more like I am
suffering from a leaning-toothpick syndrome with all the \.

Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: John Ferlan <jferlan@redhat.com>
This commit is contained in:
Eric Blake 2019-02-26 12:49:25 -06:00
parent fe1b683fd0
commit 5817dec014
4 changed files with 14 additions and 5 deletions

View File

@ -414,6 +414,9 @@ mymain(void)
/* Tests of multiple commands. */ /* Tests of multiple commands. */
DO_TEST(36, "a\nb\n", " echo a; echo b;"); DO_TEST(36, "a\nb\n", " echo a; echo b;");
DO_TEST(37, "a\nb\n", "\necho a\n echo b\n"); DO_TEST(37, "a\nb\n", "\necho a\n echo b\n");
DO_TEST(38, "a\nb\n", "ec\\\nho a\n echo \\\n b;");
DO_TEST(39, "a\n b\n", "\"ec\\\nho\" a\n echo \"\\\n b\";");
DO_TEST(40, "a\n\\\n b\n", "ec\\\nho a\n echo '\\\n b';");
# undef DO_TEST # undef DO_TEST

View File

@ -41,7 +41,8 @@ The B<virsh> program can be used either to run one I<COMMAND> by giving the
command and its arguments on the shell command line, or a I<COMMAND_STRING> command and its arguments on the shell command line, or a I<COMMAND_STRING>
which is a single shell argument consisting of multiple I<COMMAND> actions which is a single shell argument consisting of multiple I<COMMAND> actions
and their arguments joined with whitespace and separated by semicolons or and their arguments joined with whitespace and separated by semicolons or
newlines between commands. Within I<COMMAND_STRING>, virsh understands the newlines between commands, where unquoted backslash-newline pairs are
elided. Within I<COMMAND_STRING>, virsh understands the
same single, double, and backslash escapes as the shell, although you must same single, double, and backslash escapes as the shell, although you must
add another layer of shell escaping in creating the single shell argument. add another layer of shell escaping in creating the single shell argument.
If no command is given in the command line, B<virsh> will then start a minimal If no command is given in the command line, B<virsh> will then start a minimal

View File

@ -24,7 +24,8 @@ The B<virt-admin> program can be used either to run one I<COMMAND> by giving the
command and its arguments on the shell command line, or a I<COMMAND_STRING> command and its arguments on the shell command line, or a I<COMMAND_STRING>
which is a single shell argument consisting of multiple I<COMMAND> actions which is a single shell argument consisting of multiple I<COMMAND> actions
and their arguments joined with whitespace and separated by semicolons or and their arguments joined with whitespace and separated by semicolons or
newlines between commands. Within I<COMMAND_STRING>, virt-admin understands the newlines between commands, where unquoted backslash-newline pairs are
elided. Within I<COMMAND_STRING>, virt-admin understands the
same single, double, and backslash escapes as the shell, although you must same single, double, and backslash escapes as the shell, although you must
add another layer of shell escaping in creating the single shell argument. add another layer of shell escaping in creating the single shell argument.
If no command is given in the command line, B<virt-admin> will then start a minimal If no command is given in the command line, B<virt-admin> will then start a minimal

View File

@ -1659,8 +1659,8 @@ vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char **res,
*res = q; *res = q;
while (*p && (*p == ' ' || *p == '\t')) while (*p == ' ' || *p == '\t' || (*p == '\\' && p[1] == '\n'))
p++; p += 1 + (*p == '\\');
if (*p == '\0') if (*p == '\0')
return VSH_TK_END; return VSH_TK_END;
@ -1681,7 +1681,7 @@ vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char **res,
continue; continue;
} else if (!single_quote && *p == '\\') { /* escape */ } else if (!single_quote && *p == '\\') { /* escape */
/* /*
* The same as the bash, a \ in "" is an escaper, * The same as in shell, a \ in "" is an escaper,
* but a \ in '' is not an escaper. * but a \ in '' is not an escaper.
*/ */
p++; p++;
@ -1689,6 +1689,10 @@ vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char **res,
if (report) if (report)
vshError(ctl, "%s", _("dangling \\")); vshError(ctl, "%s", _("dangling \\"));
return VSH_TK_ERROR; return VSH_TK_ERROR;
} else if (*p == '\n') {
/* Elide backslash-newline entirely */
p++;
continue;
} }
} else if (!single_quote && *p == '"') { /* double quote */ } else if (!single_quote && *p == '"') { /* double quote */
double_quote = !double_quote; double_quote = !double_quote;