Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

echo a variable containing an & sometimes works, sometimes not. Why ?

12 views
Skip to first unread message

R.Wieser

unread,
Nov 20, 2022, 6:48:17 AM11/20/22
to
Hello all,

I've written a test batch showing a directory tree. In it I noticed that
echo-ing an argument containing a pathname containing an "&" causes a
problem when done directly :

echo %~xn1

but doesn't when done indirectly :

for %%a in (%1) do echo %%~xna

Does anyone have an explanation for it ?


And a question : How do I tell the batchfile parser *not* to parse the %~xn1
results but instead just display it as-is ?

I know that I can wrap it in doublequotes :

echo "%~xn1"

but those doublequotes get displayed too. :-(

Regards,
Rudy Wieser


Kerr-Mudd, John

unread,
Nov 20, 2022, 8:08:15 AM11/20/22
to
On Sun, 20 Nov 2022 12:48:12 +0100
"R.Wieser" <add...@not.available> wrote:

> Hello all,
>
> I've written a test batch showing a directory tree. In it I noticed that
> echo-ing an argument containing a pathname containing an "&" causes a
> problem when done directly :
>
> echo %~xn1
>

'&' is seen as a command concatenation symbol; e.g.
echo Missed it!&cls


> but doesn't when done indirectly :
>
> for %%a in (%1) do echo %%~xna
>
> Does anyone have an explanation for it ?

DelayedExpansion set?

>
>
> And a question : How do I tell the batchfile parser *not* to parse the %~xn1
> results but instead just display it as-is ?

Ah so you kind of knew why!
>
> I know that I can wrap it in doublequotes :
>
> echo "%~xn1"
>
> but those doublequotes get displayed too. :-(
>

Don't make directory names with '&' in them?
(Sorry, not very helpfull)


--
Bah, and indeed Humbug.

JJ

unread,
Nov 20, 2022, 8:39:25 AM11/20/22
to
On Sun, 20 Nov 2022 12:48:12 +0100, R.Wieser wrote:
> Hello all,
>
> I've written a test batch showing a directory tree. In it I noticed that
> echo-ing an argument containing a pathname containing an "&" causes a
> problem when done directly :
>
> echo %~xn1
>
> but doesn't when done indirectly :
>
> for %%a in (%1) do echo %%~xna
>
> Does anyone have an explanation for it ?

FOR's variables are not parsed. AFAIK, FOR variables are expanded *after*
the command line has been parsed. Non-DelayedExpansion normal variables in
the command line are expanded *before* the command line is parsed.

> And a question : How do I tell the batchfile parser *not* to parse the %~xn1
> results but instead just display it as-is ?
>
> I know that I can wrap it in doublequotes :
>
> echo "%~xn1"
>
> but those doublequotes get displayed too. :-(

DelayedExpansion can be used, but escape character may need to be specified
twice when it's needed. Adding complexity for normal variables usage. It may
cause a problem which is unsolvable instead.

For non-DelayedExpansion normal variables, we'd have to use FOR variable to
display it. e.g.

@echo off
setlocal
set s=abc ^& def

echo this causes error
echo %s%

echo.
echo this won't cause error
for %%A in ("%s%") do echo %%~A

R.Wieser

unread,
Nov 20, 2022, 9:18:16 AM11/20/22
to
John,

> '&' is seen as a command concatenation symbol; e.g.
> echo Missed it!&cls

Thank you, but I was aware of that. :-) To be honest, I'm thinking a bit
further and am using that "&" as a placeholder for other special-meaning
characters.

> DelayedExpansion set?

Nope, but thanks for the suggestion. Alas, I just tried to put it at
several different locations but still got the same result.

> Ah so you kind of knew why!

:-) As someone who was lucky enough to have been provided with a
functioning brain I can observe and deduce.

> Don't make directory names with '&' in them?
> (Sorry, not very helpfull)

:-p Yeah, that was one of my own thoughts too. Although that could work
for my own drives, all bets are off when I would dare to use it on someone
elses USB stick or similar.

Regards,
Rudy Wieser


R.Wieser

unread,
Nov 20, 2022, 9:35:14 AM11/20/22
to
JJ,

> AFAIK, FOR variables are expanded *after* the command line
> has been parsed. ... normal variables in the command line
> are expanded *before* the command line is parsed.

That was my conclusion too. But I see that my question was imprecise. The
"why" was aimed more at "why does it happen in two different ways".

Though I just now remembered having recently read that the batch scripting
language has evolved over time, and with evolution lots of weird things can
happen.

> DelayedExpansion can be used, but escape character may need
> to be specified twice when it's needed. Adding complexity for
> normal variables usage. It may cause a problem which is unsolvable
> instead.

Argh!

> For non-DelayedExpansion normal variables, we'd have to use FOR
> variable to display it. e.g.

:-) Yep, as I included in my initial post (the "but doesn't when done
indirectly" example).

Regards,
Rudy Wieser


Herbert Kleebauer

unread,
Nov 20, 2022, 1:54:58 PM11/20/22
to
On 20.11.2022 12:48, R.Wieser wrote:
> Hello all,

> I know that I can wrap it in doublequotes :
>
> echo "%~xn1"
>
> but those doublequotes get displayed too. :-(

I don't know how to get a & in %1 without surrounding it
in "" so I can't test it. But set/p seems to remove the "":

@echo off

call :sub "d:\a&b\c\te&st.123"
goto :eof

:sub
echo %1
set /p a="%~xn1"<nul
echo.


R.Wieser

unread,
Nov 20, 2022, 3:04:36 PM11/20/22
to
Herbert,

> set /p a="%~xn1"<nul
...
> I don't know how to get a & in %1 without surrounding it
> in "" so I can't test it.

Ive put a few lines of text ("hello&world", "&foo", "bar&") in a file,
retrieved those lines and than called your ":sub" with it like this :

for /f %%i in (words.txt) do call :sub %%i

, but for some reason your ":sub" was not called for the first two (though
no error or other output), but it was for the third/last line. IOW, I could
not test it either ...

It "ofcourse" worked fine when I enclosed the %%i argument in double-quotes,
but that also negated the test itself. :-|

> But set/p seems to remove the "":

It does seem to do that, yes. Though I think I like the

for %%a in (%1) do echo %%~nxa

trick better. :-)

I also tried a line (in the textfile) with an embedded doublequote. The it
caused the "set /p" to wait for input again. And ofcourse the simple "echo
%1" had no problems with it.

Regards,
Rudy Wieser


JJ

unread,
Nov 20, 2022, 7:51:30 PM11/20/22
to
On Sun, 20 Nov 2022 21:04:33 +0100, R.Wieser wrote:
>
> Ive put a few lines of text ("hello&world", "&foo", "bar&") in a file,
> retrieved those lines and than called your ":sub" with it like this :
>
> for /f %%i in (words.txt) do call :sub %%i
>
> , but for some reason your ":sub" was not called for the first two (though
> no error or other output), but it was for the third/last line. IOW, I could
> not test it either ...

CALL would force the command line to be parsed and expanded twice.

On the second command line processing, the `%%i` is already expanded, so it
is or should be treated as a command separator. However, it seems that
there's a bug on the second command line processing, since it may cancel the
CALL command execution. Below is a simple demo of this bug.

@echo off
setlocal
set a=hello^&world
set b=%%a%%

rem output: abc "hello&world"
call echo abc "%b%"

rem expected output: hello&world
rem but since `%b%` is not quoted, after expansion,
rem the `&` should be treated as a command reparator.
rem but it cancels the whole command line.
call echo abc %b%

echo end

> I also tried a line (in the textfile) with an embedded doublequote. The it
> caused the "set /p" to wait for input again. And ofcourse the simple "echo
> %1" had no problems with it.

Chances are that, your SET /P is like this.

set /p a="%1"<nul

Since the paramater is already quoted, the parsed command line would be like
below, where the quotes from SET /P are paired with the ones from the
contents of `%1`. Making the `hello&world` unquoted, and the `&` character
be treated as command separator.

So the quotes from the content of `%1` should be stripped first. i.e.

set /p a="%~1"<nul

R.Wieser

unread,
Nov 21, 2022, 1:42:57 AM11/21/22
to
JJ,

> However, it seems that there's a bug on the second command
> line processing, since it may cancel the CALL command execution.
...
> rem but since `%b%` is not quoted, after expansion,
> rem the `&` should be treated as a command reparator.

which is why I expected /something/ to be displayed, even just that the word
after the "&" could not be found as a command.

Thanks for the confirmation of the problem/bug.

> Chances are that, your SET /P is like this.
>
> set /p a="%1"<nul
...
> So the quotes from the content of `%1` should be stripped first. i.e.
>
> set /p a="%~1"<nul

That is what herbert offered me, I used and the problem happened with :

set /p a="%~xn1"<nul

Minimal example :
- - - - - - - - - - - - - - -
call :sub hello^"world
goto :eof
:sub
set /p a="%~1"<nul
goto :eof
- - - - - - - - - - - - - - -
Strange though, the string 'hello"world' gets displayed (IOW: with its
embedded doublequote). No idea how it can cause the following "<nul" to be
ignored.

Brainfart: I just remembered that there is no rule that the redirection has
to be done at the end. To get rid of /this/ problem tried putting it at the
start, and the problem was gone.

<nul set /p a="%~1"

IOW, it /is/ a parsing problem, but I've got no idea how.


Just to check I've also tested putting it somewhere in the middle, and all
of the below three work as well. A nice way to throw someone in a spin.
:-)

set <nul /p a="%~1"
set /p <nul a="%~1"
set /p a<nul="%~1"

Regards,
Rudy Wieser


JJ

unread,
Nov 21, 2022, 6:16:58 AM11/21/22
to
On Mon, 21 Nov 2022 07:42:45 +0100, R.Wieser wrote:
>
> Just to check I've also tested putting it somewhere in the middle, and all
> of the below three work as well. A nice way to throw someone in a spin.
> :-)
>
> set <nul /p a="%~1"
> set /p <nul a="%~1"
> set /p a<nul="%~1"

I need someone's head so I could pull his hairs out.
0 new messages