1
Set a=%~1
echo %a%>>"C:\file.txt"

Im calling the script via cmd "C:\batch.bat" "$Multi Line String$"

The output file is only having the text till the first line break. Please Help

Ramesh Eol
  • 41
  • 8
  • 3
    How do you specify the multi-line string? Please provide an example! – aschipfl Mar 16 '17 at 20:14
  • 1
    @abelenky: It is very simple: `set LF=^` & `%Two empty%` & `%lines%` & `set "var=Line one!LF!Line two!LF!Line three"`, but it is not common... @RameshEol: perhaps `echo !a!` do the trick (it works here). – Aacini Mar 16 '17 at 22:45
  • 1
    There is no way to pass a value with multi-line text _in a Batch file parameter_. You should pass _the name_ of the multi-line text variable instead and expand it using DelayedExpansion this way: `Set a=%~1` & `echo !%a%!>>"C:\file.txt"` – Aacini Mar 16 '17 at 22:59
  • echo !a!>>"C:\file.txt" dint work – Ramesh Eol Mar 17 '17 at 07:57
  • im passing the multi line string from another application. It is a field which is having multi line text. Something like. Line1: Test. Line2: Testing. Line3: Tested. – Ramesh Eol Mar 17 '17 at 08:00
  • I am only getting Line1: Test in my output file file.txt – Ramesh Eol Mar 17 '17 at 08:02
  • I didn't said `echo !a!`, but `echo !%a%!` or simpler: `echo !%~1!`, but both forms require `setlocal EnableDelayedExpansion`. Is the "another application" a Batch file? Are you sure that the value is in an _environment variable_? Please, show the code of the other application that calls this Batch file! – Aacini Mar 17 '17 at 14:53

2 Answers2

2

As I said in a comment, there is no way to pass a value with multi-line text in a Batch file parameter. You should pass the name of the multi-line text variable instead and expand it using DelayedExpansion. This is an example of such a method:

@echo off
setlocal EnableDelayedExpansion

rem Create a variable with just LineFeed
set LF=^
%Don't remove%
%these two lines%

rem Create the variable with multi-line text
set "MultiLineString=Line1: Test.!LF!Line2: Testing.!LF!Line3: Tested."

rem Call the Batch script passing *THE NAME* of the variable
cmd /C batch.bat MultiLineString

And this is your same batch.bat script with the changes I suggested:

@echo off
setlocal EnableDelayedExpansion

Set a=%~1
echo !%a%!> file.txt

echo File created:
type file.txt

Output:

File created:
Line1: Test.
Line2: Testing.
Line3: Tested.

This method works as long as the calling program have stored the multi-line string in an environment variable, that is the only type of variables that can be accessed by a Batch file. For this reason, it is important for us to know how you created the multi-line string; otherwise, we have no means to solve this problem...

EDIT: New method added

After I read the improvements to jeb's answer I must admit that I was wrong: it is possible to pass the value of a multi-line variable in a Batch file parameter. This is my own version of such a method:

@echo off
setlocal EnableDelayedExpansion

rem Create a variable with just LineFeed
(set LF=^
%empty line%
)

rem Create the variable with multi-line text
set "MultiLineString=Line1: <Test>.!LF!Line2: |Testing|.!LF!Line3: &Tested&."

rem Prepare the multi-line variable and call the receiver Batch file
call :callBatch
echo Back to caller...
goto :EOF


:callBatch

rem Prepare the multi-line variable
set "lines="
for /F "delims=" %%a in ("!MultiLineString!") do (
   if not defined lines (
      set "lines=%%a "
   ) else (
      set "line=%%a"
      for %%b in ("&=^&" "<=^<" ">=^>" "|=^|") do set "line=!line:%%~b!"
      set "lines=!lines!!LF!!line!"
   )
)
REM echo [!lines!]

rem Call the receiver Batch file
(batch.bat "!lines!")
exit /B

And this is the new version of the companion batch.bat file:

@echo off
setlocal EnableDelayedExpansion
(
   prompt $S
   echo on
   for %%a in (_) do if a==b (
      %1
   )
) > param.tmp

@echo off
(for /F "skip=2 delims=" %%a in (param.tmp) do if "%%a" neq ")" (
   set "line=%%a"
   echo(!line:~1,-2!
)) > file.txt
del param.tmp

echo File created:
echo/
type file.txt

This version correctly manage most special Batch characters, excepting exclamation-mark. This is the output:

File created:

Line1: <Test>.
Line2: |Testing|.
Line3: &Tested&.

Back to caller...

PS - This method will not work if the receiver batch.bat file is executed from outside another batch file, that is, via the standard cmd /C batch.bat "$Multi Line String$" method.

Community
  • 1
  • 1
Aacini
  • 65,180
  • 12
  • 72
  • 108
  • There is always a way, see my answer :-) But your solution is still bettter – jeb Mar 18 '17 at 21:51
  • I appended a "full solution", please review it – jeb Mar 20 '17 at 09:47
  • Your solution uses the simpler `if a==b` construct, and your escaping for special characters is good but the caret is missing `"^=^^"`. The main problem still stands, your version can't get carets at all `Line1 ^ caret!LF!Line2 ^ caret` (Mine gets only the caret in line1). And the main problem is that our code fails always for `Line1!LF!if diff piff` – jeb Mar 21 '17 at 10:41
2

Obviously, there is a way to to pass a value with multi-line text in a Batch file parameter.
But it is a little bit complex and currently there isn't a way to get the content out of the parameter in a safe way for any possible content.

A simple demonstration

Producer.bat - puts "Line1<line feed>Line2" into %1

@echo off
setlocal EnableDelayedExpansion
(set LF=^
%=empty=%
)
set ^"pVar=^^^^^"Line1^^^^!LF!!LF!line2""
call Receiver.bat %%pVar%% #

Receiver.bat

@echo off
prompt :
@echo on
(
@exit /b
REM # %~1 #
)

Output

:(

REM # Line1
line2 #
)

To fetch this, the solution from How to receive even the strangest command line parameters? can be extended.

The problem is, that it only works with simple content, but there exists content which can't be received without producing parser errors.
Like: "Line1<line feed>Line2"

Therefore I would recommend Aacini's solution

Edit: Improved samples

A batch file to call another batch file with multi line variables.

@echo off
setlocal EnableDelayedExpansion
(set \n=^
%=empty=%
)

set "var=Line1!\n!line2!\n!line3!\n!line4"
call :callBatch var
exit /b


:callBatch
setlocal EnableDelayedExpansion
set "prepVar=!%~1!"
for %%L in ("!\n!") DO (
    for %%b in ("^=^^" "&=^&" "<=^<" ">=^>" "|=^|") do set "prepVar=!prepVar:%%~b!"
    set "prepVar=^^"!prepVar:%%~L=^^%%~L%%~L!""
)
rem echo !prepVar!-
call receiver.bat %%prepVar%%
exit /b

And a receiver.bat that accepts and parses a multi line value from %1.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
prompt :
(
    @echo on
    for %%a in (4) do (
        @goto :next
        rem # %~1#
    )
) > param.tmp
:next
@echo off
endlocal
setlocal DisableDelayedExpansion
set lineNo=0
(
for /F "skip=3 delims=" %%L in (param.tmp) do (
    set /a lineNo+=1
    set "line=%%L"
    setlocal EnableDelayedExpansion
    if !lineNo! EQU 1 (
        set "line=!line:*# =!"
        set "line=!line:~,-2!"
    ) ELSE IF "!line!"==") " (
        goto :exit
    ) ELSE (
        set "line=!line:* =!"
        set "line=!line:~,-1!"
    )
    (echo(!line!)
    endlocal
)
) > file.txt
:exit

type file.txt

Edit2: Unsolved problems
It's possible to fetch any content in line1, but all other lines have restrictions for their content.
The content has to be "parse conform", that means that a multi line parameter with this content fails

Line1
If a=

It's because the first line can be secured with REM, but all other lines have to be valid lines.
Carets are only visible in line1 (with the REM technic).
And lines beginning with @ are empty and : are removed completly.

Community
  • 1
  • 1
jeb
  • 78,592
  • 17
  • 171
  • 225
  • Ok! IMHO the academic discussion of abstract points is right in DosTips, but in this site you should post working solutions! **`;)`**. Two points: **1.** You forgot a right parenthesis in this line: `> file.txt`. **2.** Your method does not manage special Batch characters. I added my own solution based on your new method, please review it... – Aacini Mar 20 '17 at 23:08
  • @Aacini Thanks I fixed the two points and add the description of the unsolved problems – jeb Mar 21 '17 at 10:50