Multiline text file, how to put into an environmen

2019-02-17 15:31发布

问题:

i have a file called file.txt which contains:

     this is line one ^
     this is line two ^
     this is the last line

how can i put that into an env var?

i can do this from a batch file: test.bat

    set LF=^
    [blank line]
    [blank line]
    rem two blank lines needed above
    set multi=Line 1!LF!Line 2!LF!Last line
    echo !multi!

this outputs three lines:

      Line 1
      Line 2
      Last line

so how can i get file.txt into envvar inside a batch file?

回答1:

As dbenham said, it can be done also with for/f but it's a bit more complicated.

The simple 80% solution is

setlocal EnableDelayedExpansion

set "var="
set LF=^


rem *** Two empty lines are required for the linefeed
FOR /F "delims=" %%a in (myFile.txt) do (
  set "var=!var!!LF!%%a"
)
echo !var!

But it fails with:
- If a line is blank it will be skipped
- If a line begins with ; the EOL-character
- If a line contains ! (and carets)

But then you could use a bit more complex solution

@echo off
SETLOCAL DisableDelayedExpansion
set "all="
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ aux1.txt"`) do (
    set "line=%%a"
    SETLOCAL EnableDelayedExpansion
    set "line=!line:#=#S!"
    set "line=!line:*:=!"
    for /F "delims=" %%p in ("!all!#L!line!") do (
        ENDLOCAL
        set "all=%%p"
    )
)
SETLOCAL EnableDelayedExpansion
if defined all (
set "all=!all:~2!"
set ^"all=!all:#L=^

!"
set "all=!all:#S=#!"
)
echo !all!

What the code do?
First, the findstr /n ^^ will prepend each line with a line number and a colon, like

1:My first Line
2:; beginning with a semicolon
3:
4:there was an empty line

This solves the problem of empty lines and also the standard EOL-character ; can be ignored.
To get the content of the line, the value is set to a variable while delayed expansion is disabled, this solves the problem with ! and ^ characters.

To remove the line number and the colon, the delayed expansion will be enabled (no, a delim of : can't solve it).

Then all # are replaced with #S, this will be done first, as after the prefix removing the line could be empty and the replacement would fail.
But why I replace it?
That's because I can't insert the linefeeds here, as the following FOR/F would fail with embedded linefeeds,
so I only add linefeed marker (in this case I use #L), but the content of the file could contain also a #L, but by replacing all # with #S all markers are unique.

After the marker, there is the problem to close/disable the delayed expansion with an endlocal, but preserve the content of the modified all and line variable.
This is done with the FOR/F-endlocal trick, as the %%p can transport content behind the endlocal barrier.

Then after reading the complete file, I check if the all is defined, as it would be empty for an empty file.
Then the first linefeed marker #L will be removed, and all other markers are replaced with a real linefeed character.
Then the sharp safer #S will be reverted to #.

That's all, so even this solution is obviously...



回答2:

You were almost there. You need to read each line of text and then append the line plus a line feed to the variable.

FOR /F could be used, but it doesn't play well with delayed expansion if the content contains ! characters. It is also awkward to preserve blank lines and awkward to disable the EOL option.

A simpler solution is to use SET /P to read the lines. The limitations with this technique are:

1) It trims trailing control characters from each line

2) The file must use Windows standard line terminators of carriage return, line feed. It will not work with Unix style line feed.

3) It is limited to reading 1023 bytes per line (not including the line terminator characters)

Bear in mind that an environment variable can only hold a little less than 8 kbytes of data. So you are limited to only loading a very small file into a variable with this technique.

@echo off
setlocal enableDelayedExpansion
set LF=^


:: Two blank lines above needed for definition of LF - do not remove
set file="test.txt"
set "var="
for /f %%N in ('find /c /v "" ^<%file%') do set lineCnt=%%N
<%file% (
  for /l %%N in (1 1 %lineCnt%) do (
    set "ln="
    set /p "ln="
    set "var=!var!!ln!!lf!"
  )
)
set var