user170324
user170324

Reputation: 45

Batch File - Insert Line into file

I'm trying to insert a line into a file using the following code (from Write batch variable into specific line in a text file)

@echo off
setlocal enableextensions enabledelayedexpansion

set inputfile=variables.txt

set tempfile=%random%-%random%.tmp

copy /y nul %tempfile%

set line=0

for /f "delims=" %%l in (%inputfile%) do (
   set /a line+=1
   if !line!==4 (
       echo WORDS YOU REPLACE IT WITH>>%tempfile%
   ) else (
    echo %%l>>%tempfile%
)
)

del %inputfile%
ren %tempfile% %inputfile%

endlocal

My problem is the file has comment lines (which start with semicolons) which need to be kept

; directory during network startup. This statement must indicate a local disc
; drive on your PC and not a network disc drive.
LOCALDRIVE=C:\TEMP;

; PANELISATION PART/NET NAMING CONVENTION
; When jobs are panelised, parts/nets are renamed for each panel step by

When I run the batch file, it ignores the semicolon lines, So I only get:

LOCALDRIVE=C:\TEMP;

What do I need to do to keep the semicolon lines?

Upvotes: 1

Views: 4430

Answers (3)

dbenham
dbenham

Reputation: 130819

The EOL option determines what lines are to be ignored. The default value is a semicolon. If you know a character that can never appear in the first position of a line, then you can simply set EOL to that character. For example, if you know a line can't start with |, then you could use

for /f "eol=| delims=" %%l in (%inputfile%) do ...

There is an awkward syntax that disables EOL completely, and also disables DELIMS:

for /f delims^=^ eol^= %%l in (%inputfil%) do ...

Note that FOR /F always discards empty lines, so either of the above would result in:

; directory during network startup. This statement must indicate a local disc
; drive on your PC and not a network disc drive.
LOCALDRIVE=C:\TEMP;
; PANELISATION PART/NET NAMING CONVENTION
; When jobs are panelised, parts/nets are renamed for each panel step by

A trick is used if you want to preserve empty lines. Use FIND or FINDSTR to insert the line number before each line, and then use expansion find/replace to remove the line number. Now you know the line never begins with ;, so you can ignore the EOL option.

for /f "delims=" %%L in ('findstr /n "^" "%inputfile%"') do (
  set "ln=%%L"
  set "ln=!ln:*:=!"
  REM You now have the original line, do whatever needs to be done here
)

But all of the above have a potential problem in that you have delayed expansion enabled when you expand the FOR variable, which means that any content containing ! will be corrupted. To solve this you must toggle delayed expansion on and off within the loop:

setlocal disableDelayedExpansion
...
for /f "delims=" %%L in (findstr /n "^" "%inputfile%") do (
  set "ln=%%L"
  setlocal enableDelayedExpansion
  set "ln=!ln:*:=!"
  REM You now have the original line with ! preserved, do whatever needs done here
  endlocal
)

Also, when ECHOing an empty line, it will print out ECHO is off unless you do something like

echo(!ln!

It takes time to open and position the write cursor to the end every time you use >> within the loop. It is faster to enclose the entire operation in one set of parentheses and redirect once. Also, you can replace the DEL and REN with a single MOVE command.

Here is a final robust script:

@echo off
setlocal disableDelayedExpansion
set "inputfile=variables.txt"
set line=0
>"%inputfile%.new" (
  for /f "delims=" %%L in (findstr /n "^" "%inputfile%") do (
    set "txt=%%L"
    set /a line+=1
    setlocal enableDelayedExpansion
    set "txt=!txt:*:=!"
    if !line! equ 4 (
      echo New line content here
    ) else (
      echo(!txt!
    )
    endlocal
  )
)
move /y "%inputfile%.new" "%inputfile%" >nul
endlocal

That is an awful lot of work for such a simple task, and it requires a lot of arcane knowledge.

There is a much quicker hack that works as long as

  • your first 4 lines do not exceed 1021 bytes
  • none of your first 3 lines have trailing control characters that need to be preserved
  • the remaining lines do not have <tab> characters that must be preserved (MORE converts <tab> into a string of spaces.
@echo off
setlocal enableDelayedExpansion
set "inputfile=variables.txt"
>"%inputfile%.new" (
  <"%inputfile%" (
    for /l %%N in (1 1 3) do (
      set "ln="
      set /p "ln="
      echo(!ln!
    )
  )
  echo New line content here
  more +4 "%inputfile%"
)
move /y "%inputfile%.new" "%inputfile%"

That is still a lot of work and arcane knowledge.

I would use my JREPL.BAT utility

Batch is really a terrible tool for text processing. That is why I developed JREPL.BAT to manipulate text using regular expressions. It is a hybrid JScript/batch script that runs natively on any Windows machine from XP onward. It is extremely versatile, robust, and fast.

A minimal amount of code is required to solve your problem with JREPL. Your problem doesn't really require the regular expression capabilities.

jrepl "^" "" /jendln "if (ln==4) $txt='New content here'" /f "variables.txt" /o -

If used within a batch script, then you must use call jrepl ... because JREPL.BAT is also a batch script.

Upvotes: 3

aphoria
aphoria

Reputation: 20189

By default, the FOR command treats ; as the end-of-line character, so all those lines that start with ; are being ignored.

Add eol= to your FOR command, like this:

for /f "eol= delims=" %%l in (%inputfile%) do (

Upvotes: 1

StormyKnight
StormyKnight

Reputation: 607

It looks like you're echoing just the line delimiter, not the whole line:

echo %%l>>%tempfile%

I'm rusty on ms-dos scripts, so I can't give you more than that.

Upvotes: 0

Related Questions