heredoc in batch

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
siberia-man
Posts: 208
Joined: 26 Dec 2013 09:28
Contact:

heredoc in batch

#1 Post by siberia-man » 07 Jun 2015 11:47

heredoc is way to determine multiline string literals in scripts. Unfortunately heredoc is not included to native batch scripts. The following link shows the way to embed heredoc in batch very close to the original definition: http://stackoverflow.com/a/29329912/3627676

I have made some modifications to allow heredoc be declared with the external script "heredoc.bat" or the embedded subroutine ":heredoc". To achieve the goal I used the idea described in the topic Tricky way to detect calls from another batch script.

Code: Select all

:: http://forum.script-coding.com/viewtopic.php?pid=94390#p94390
@if not defined CMDCALLER @(
   (echo on & goto) 2>nul
   call set "CMDCALLER=%%~f0"
   call "%~f0" %*
   set "CMDCALLER="
)
@if /i "%CMDCALLER%" == "%%~f0" set "CMDCALLER="


@echo off

if defined CMDCALLER (
   call :heredoc %*
   goto :EOF
)


call :heredoc :HEREDOCHELP & goto :EOF
heredoc: attempt to embed the idea of heredoc to batch scripts.

There are few ways for using this solution:

1. call heredoc :LABEL & goto :LABEL
Calling the external script "heredoc.bat" passing the heredoc LABEL.

2. call :heredoc :LABEL & goto :LABEL
Embed the subroutine ":heredoc" into yuor script.

NOTES:
Both LABEL and :LABEL forms are possible. Instead of "goto :LABEL" it is
possible to use "goto" with another label, or "goto :EOF", or "exit /b".

Variables to be evaluated within the heredoc should be called in the
delayed expansion style ^("^!var^!" rather than "%var%", for instance^).

Literal exclamation marks "^!" and carets "^^" must be escaped with a
caret "^".

Additionally, parantheses "(" and ")" should be escaped, as well, if they
are part of the heredoc content within parantheses of the script block.
:HEREDOCHELP


:: http://stackoverflow.com/a/15032476/3627676
:heredoc LABEL
setlocal enabledelayedexpansion
if not defined CMDCALLER set "CMDCALLER=%~f0"
set go=
for /f "delims=" %%A in ( '
   findstr /n "^" "%CMDCALLER%"
' ) do (
   set "line=%%A"
   set "line=!line:*:=!"

   if defined go (
      if /i "!line!" == "!go!" goto :EOF
      echo:!line!
   ) else (
      rem delims are ( ) > & | TAB , ; = SPACE
      for /f "tokens=1-3 delims=()>&|   ,;= " %%i in ( "!line!" ) do (
         if /i "%%i %%j %%k" == "call :heredoc %1" set "go=%%k"
         if /i "%%i %%j %%k" == "call heredoc %1" set "go=%%k"
         if defined go if not "!go:~0,1!" == ":" set "go=:!go!"
      )
   )
)
goto :EOF

mirrormirror
Posts: 129
Joined: 08 Feb 2016 20:25

Re: heredoc in batch

#2 Post by mirrormirror » 18 Jul 2016 17:14

Hello Siberia-man, I was attempting to use your heredoc.bat but am not able to get it to work:

Code: Select all

@ECHO OFF
@ECHO BEGIN ---------------------------------------------
CALL heredoc.bat :testlabel1 & goto :testlabel1

      DELETE FROM Users;
      DROP TABLE IF EXISTS tmpDataInsert;
      
      CREATE TEMP TABLE IF NOT EXISTS [tmpDataInsert] ( [uName] CHAR );
      .import SQLImport_UsernNm.txt tmpDataInsert
      
      INSERT INTO Users(UserNm) SELECT * FROM tmpDataInsert;
      DROP TABLE IF EXISTS tmpDataInsert;


:testlabel1

@ECHO END ---------------------------------------------


Output:

Code: Select all

T:\>test.cmd
BEGIN ---------------------------------------------
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
,;= " was unexpected at this time.
END ---------------------------------------------
T:\>


Can you advise?

siberia-man
Posts: 208
Joined: 26 Dec 2013 09:28
Contact:

Re: heredoc in batch

#3 Post by siberia-man » 19 Jul 2016 00:00

Hi mirrormirror,

There is error that comes from the line 60 of the heredoc.bat script. Most probably you have entered error while copying from the forum. Please check that you have stored the script correctly. You can take this from the repository https://github.com/ildar-shaimordanov/c ... eredoc.bat. This is original, working and always actual version of the script.
Last edited by siberia-man on 07 Aug 2019 12:06, edited 2 times in total.

mirrormirror
Posts: 129
Joined: 08 Feb 2016 20:25

Re: heredoc in batch

#4 Post by mirrormirror » 19 Jul 2016 17:10

Thank you for the reply. I've downloaded the file from the link you sent and the errors are now gone but it doesn't seem to work as expected:

Code: Select all

@ECHO OFF

CALL heredoc.bat :testlabel1 & GOTO :testlabel1
SET DataFile=users.txt
@ECHO BEGIN ---------------------------------------------
:SQLFile_Begin
      DELETE FROM Users;
      DROP TABLE IF EXISTS tmpDataInsert;
      
      CREATE TEMP TABLE IF NOT EXISTS [tmpDataInsert] ( [uName] CHAR );
      .separator "|"
      .import %DataFile% tmpDataInsert
      
      INSERT INTO Users(UserNm) SELECT * FROM tmpDataInsert;
      DROP TABLE IF EXISTS tmpDataInsert;

:SQLFile_END
:testlabel1

@ECHO END ---------------------------------------------
GOTO:END

Output:

Code: Select all

T:\>test.cmd
END ---------------------------------------------

T:\>

Shouldn't everything between the "CALL heredoc..." and ":testlabel1" be printed out?

siberia-man
Posts: 208
Joined: 26 Dec 2013 09:28
Contact:

Re: heredoc in batch

#5 Post by siberia-man » 20 Jul 2016 01:19

I've tested your example. In fact, it doesn't work because you try to call the script by name and extension .bat. Try the same without extension.

Code: Select all

C:\>type z.bat
@ECHO OFF

CALL heredoc :testlabel1 & GOTO :testlabel1
SET DataFile=users.txt
@ECHO BEGIN ---------------------------------------------
:SQLFile_Begin
      DELETE FROM Users;
      DROP TABLE IF EXISTS tmpDataInsert;

      CREATE TEMP TABLE IF NOT EXISTS [tmpDataInsert] ( [uName] CHAR );
      .separator "|"
      .import %DataFile% tmpDataInsert

      INSERT INTO Users(UserNm) SELECT * FROM tmpDataInsert;
      DROP TABLE IF EXISTS tmpDataInsert;

:SQLFile_END
:testlabel1

@ECHO END ---------------------------------------------
GOTO:END


C:\>z
SET DataFile=users.txt
@ECHO BEGIN ---------------------------------------------
:SQLFile_Begin
DELETE FROM Users;
DROP TABLE IF EXISTS tmpDataInsert;

CREATE TEMP TABLE IF NOT EXISTS [tmpDataInsert] ( [uName] CHAR );
.separator "|"
.import %DataFile% tmpDataInsert

INSERT INTO Users(UserNm) SELECT * FROM tmpDataInsert;
DROP TABLE IF EXISTS tmpDataInsert;

:SQLFile_END
END ---------------------------------------------
The system cannot find the batch label specified - END


I'd like to notice that the script outputs everything between the lines call heredoc :LABEL and :LABEL and doesn't execute them.

mirrormirror
Posts: 129
Joined: 08 Feb 2016 20:25

Re: heredoc in batch

#6 Post by mirrormirror » 20 Jul 2016 18:10

it doesn't work because you try to call the script by name and extension .bat. Try the same without extension.

Thank you siberia-man, it is working now.

Post Reply