Multi-line indentation

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
treintje
Posts: 6
Joined: 14 Oct 2016 16:00

Multi-line indentation

#1 Post by treintje » 14 Oct 2016 16:22

I'm looking for an explanation why I cannot put the carrot behind the OR operator:

Code: Select all

md "dir" ||^
  echo Failed to make dir

But putting the carrot in front of OR seems to be fine.

Code: Select all

md "dir" ^
  || echo Failed to make dir

And is there a way to put the opening parenthesis of an if-block onto the next line?

Code: Select all

if "%x%" == "%y%" ^
(
  echo Match found
)

Squashman
Expert
Posts: 4471
Joined: 23 Dec 2011 13:59

Re: Multi-line indentation

#2 Post by Squashman » 14 Oct 2016 21:08

A double pipe is not an OR. It is conditional execution. If the previous command fails then execute the next command. A double ampersand executes the next command if the previous command was successful.

treintje
Posts: 6
Joined: 14 Oct 2016 16:00

Re: Multi-line indentation

#3 Post by treintje » 15 Oct 2016 03:44

It seems that I used the wrong terminology for the double pipe operator. I still don't understand the ruling of the ^ anchor operator, an explanation why certain codes can be split up to the next line and others don't, would be very much appreciated.

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Multi-line indentation

#4 Post by foxidrive » 15 Oct 2016 06:29

treintje wrote:I still don't understand the ruling of the ^ anchor operator


It would help to know what you are actually doing with your code as the answers can be very different, and we end up wasting our time.

The caret is a line-continuation character, and also an escape character.

penpen
Expert
Posts: 1999
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Multi-line indentation

#5 Post by penpen » 15 Oct 2016 06:33

The escape character circumflex accent ('^') is working finde even after conditional execution.
But you are underestimating the consequences:
The next character is treated as no special character (by the scanner of the command line interpreter).

In your first example the next character to the scanner is the space character in the next line.
This space is now handled as a normal character (and not as a separator character).
After this character a second space character is found, which is a separator.
So the space is the first token of a single instruction which is defined as the command-
This command (" ") is unknown.

So you have to remove all characters in front of echo to make this example work:

Code: Select all

md "dir" ||^
echo Failed to make dir
(The 'e' is treated as a normal character, which is its default meaning.)

For the same reason the '(' is treated as a normal charcter.
But you cannot add seperator characters in front of the '(' to let the opening parenthesis be a special character for the above reason.
So you have to redirect stderr to nul (you don't want to see the error message 'command " " unknown', or similar) and add an ampersand to execute multiple commands:

Code: Select all

if "%x%" == "%y%" ^
  2>nul & (
  echo Match found.
) else (
  echo Match not found.
)


Sidenote:
A "scanner"/"lexer" reads the source code lines and transforms each line into a sequence of (so called) tokens (smallest meaningful units) and is a part of an interpreter.


penpen

treintje
Posts: 6
Joined: 14 Oct 2016 16:00

Re: Multi-line indentation

#6 Post by treintje » 15 Oct 2016 08:33

Thank you for your explanation, penpen. It is really helpful to me.
penpen wrote:The next character is treated as no special character (by the scanner of the command line interpreter).
This is particularly useful to know.

To get a better understanding of how the "scanner/lexer" works, I did some tests and managed to get some sort of GNU style indenting to work with the if command.

Code: Select all

if "%x%"^ == "%y%"^
  (
    echo Match found
  )

I am aware that there are a lot of drawbacks by doing this and it only seems to work when at least two leading spaces are used in front of the open parenthesis '('. It seems as if the if command is actually comparing '"%x%"^ ' with '"%y%"^ ' (note the trailing spaces). Is that correct?

penpen
Expert
Posts: 1999
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Multi-line indentation

#7 Post by penpen » 15 Oct 2016 12:24

Yes, that is correct.

If you are interested in details, you should also note, that typically there are multiple scanners involved in interpreting a batch file.
(In common we don't differ between all these scanners and treat it as one scanner only.)

The command line interpreter (cli) itself divides each instruction into one 'command', one 'argument' and one redirection string:
The redirection is applied, the command is executed with the given argument string, and the redirections are 'restored'.
(If echo is on, the command that will be executed is first displayed in a normalized form (redirections are always last).)

But the cli also uses different parsers; for example when accessing the single command line parameters versus the command line parameter string (for example unescaped ',' characters outside doublequotes are stripped of %1 while they are present in %*).

Each command that is executed may also have its own parser; the following "test.bat" could be used to show one difference between call/batch and js/csrcipt:

Code: Select all

@if (true == false) @end /*
@echo off
setlocal enableDelayedExpansion enableExtensions

cscript //E:JScript //Nologo "%~f0" %*
call :3arguments %*

endlocal
goto :eof

:3arguments
   echo %%1 = %1
   echo %%2 = %2
   echo %%3 = %3

   goto :eof
*/
for (var i = 0; i < WScript.Arguments.length; ++i) {
   WScript.echo("WScript.Arguments.Item(" + i + ") = " + WScript.Arguments.Item(i));
}

This shows one difference:

Code: Select all

Z:\>test.bat ^^^^"1" "2^" "3"
WScript.Arguments.Item(0) = ^1
WScript.Arguments.Item(1) = 2^
WScript.Arguments.Item(2) = 3
%1 = "1"
%2 = "2^^"
%3 = "3"


penpen

Squashman
Expert
Posts: 4471
Joined: 23 Dec 2011 13:59

Re: Multi-line indentation

#8 Post by Squashman » 15 Oct 2016 16:25

Here is some good documentation that Jeb put together on SO.
http://stackoverflow.com/a/4095133/1417694

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Multi-line indentation

#9 Post by foxidrive » 20 Oct 2016 02:56

treintje wrote:To get a better understanding of how the "scanner/lexer" works, I did some tests and managed to get some sort of GNU style indenting to work with the if command.

Code: Select all

if "%x%"^ == "%y%"^
  (
    echo Match found
  )

I am aware that there are a lot of drawbacks by doing this and it only seems to work when at least two leading spaces are used in front of the open parenthesis '('.


Excuse me if I seem to be a little ranty these days but this bloke asked a question and had this example as the third item. It seems as though this is what he was trying to achieve in the first place.

penpen you've gone to a lot of effort to decribe highly technical items to this person and you do a good job of it, as you normally do.


What cheeses me off is people asking a question with misleading ways of asking that question.


As an aside:
For the life of me I can't see any good reason to use non-standard ways of laying out code in a batch script, unless you're trying to confuse some poor bunny down the track who has to decipher that code. Maybe the next employee that follows in that role.

I'll pop a couple of anti-ranty pills and see how they kick in. Maybe half a bottle of Johnny Walker instead. ;)

Post Reply