Help - Search - Members - Calendar
Full Version: Prepend or "interpend" text to a text file via batch script
MSFN Forums > Coding, Scripting and Servers > Programming (C++, Delphi, VB, etc.)

   
Google Internet Forums Unattended CD/DVD Guide
straytoasters
I can add text to a text file via batch with:
echo this is a new line>>filename.txt

What I want to do is put the new line at the beginning or somewhere in between. The "somewhere in between" is a static blank line so it would appear at the same place in every file I want to change. Any thoughts?

Straytoasters
Mijzelf
At the beginning:
CODE
echo this is a new line>temp.txt
type filename.txt>>temp.txt
delete filename.txt
rename temp.txt filename.txt

Yzöwl
For 'interpend', although I'd generally suggest SED or G(nu)AWK for the task it can also be done in 'Pure' NT Command Script.

The method would greatly depend upon the content of both the 'text file' and 'text string'.

If you provide details I may provide a reasonable solution.
Scr1ptW1zard
Based on the information provided, the following may get you started:

CODE
@echo off

set offset=30
set filename=test.txt
set tempfile=temp.tmp
set linecount=0

::: Delete files if they exist
if exist %filename% del %filename%
if exist %tempfile% del %tempfile%

:: Populate file with dummy data for testing
for /l %%n in (1,1,35) do echo %%n>>%filename%

:: Loop through file to find line offset
setlocal enabledelayedexpansion
for /f %%# in (%filename%) do (
  set /a linecount=!linecount!+1
  if !linecount! EQU %offset% (
    echo %%# Offset reached!>>%tempfile%
  ) else (
    echo %%#>>%tempfile%
  )
)
endlocal


The above simply allows you to change a line given the line number specified by the offset variable. A new file is created with the changes made. Additional changes could be made to check for a specific string at the offset line. Also, there is currently no error checking. If a file does not contain a given line offset, what should be done?

Hope that helps!
Yzöwl
Although this is slightly off topic, in order for you to understand what problems can arise from a lack of full information for the content here is an example text file:
existing.txt
CODE
I am the first line of this document.
I once stated, "I am the second line".
I demand to stay put! I don't wish to move!

Do you wish to stop & start notepad, just start it, or neither? 
 
My email, <something@somedomain.ext>, is not working!
Note
Line 5 includes a trailing space after the question mark and line 6 contains a single space, both must be retained in the output file, NewFile.ext as must the blank line currently at line 4.
I would be interested to see a reasonably concise Windows NT Command Script using no third party programs which will add the text Text string added! into the file at line 3

I have started the script, anyone up for the challenge?
AddItIn.cmd
CODE
@Echo off&Setlocal
:: Existing Filename [to add text to]
Set "EF=existing.txt"
:: Line Number [to insert string]
Set "LN=3"
:: Text String [to add]
Set "TS=Text string added!"
:: New Filename [as updated document]
Set "NF=NewFile.ext"
Type Nul>%NF%
gunsmokingman
Yzöwl here is my entry and it more of a cheat, sorry but Windows NT Command Script is not my best.
Save as a StringManipulation.vbs
QUOTE
CODE
Option Explicit
Const ForReading = 1
Const ForWriting = 2
Dim Fso :Set Fso = CreateObject("Scripting.FileSystemObject")
Dim C1, TFile1, TFile2, Ts, Txt1, Txt2
  TFile1 = "existing.txt"
  TFile2 = "NewFile.ext"
'/-> Check For File Exists
  If Fso.FileExists(TFile1) Then
   ProcessFile()
  Else
   MsgBox "Can not find " & TFile1, 4128, "Missing File"
  End If
'/-> Process The Text File If Exists
  Function ProcessFile()
   Set Ts = Fso.OpenTextFile(TFile1, ForReading)
    Do Until Ts.AtEndOfStream
     Txt1 = Ts.ReadLine
     C1 = C1 + 1
     If C1 = 3 Then Txt2 = Txt2 &  "Text string added!" & vbCrLf
      Txt2 = Txt2 & Txt1 & vbCrLf
    Loop
    Set Ts = Fso.OpenTextFile(TFile2,ForWriting,True)
    Ts.WriteLine Txt2
    Ts.Close
    CreateObject("Wscript.Shell").Run ("Notepad.exe " & Chr(34) & TFile2 & Chr(34)),1,True
'/-> UnComment If You Want To Delete The File
   ' Fso.DeleteFile(TFile2),True
   End Function
Scr1ptW1zard
Ok, after a few days of scratching my head and trying many elaborate combinations, I have come up with the following:

CODE
@echo off

set linecount=0
:: Existing Filename [to add text to]
Set "EF=existing.txt"
:: Line Number [to insert string]
Set "LN=3"
:: Text String [to add]
Set "TS=Text string added!"
:: New Filename [as updated document]
Set "NF=NewFile.ext

echo %TS%>insert.txt

if exist top.txt del top.txt
for /f "tokens=*" %%l in (%EF%) do (
call :inc linecount
call :print %%l
)

call :dec LN

more +%LN% %EF%>last.txt

copy /b top.txt+insert.txt+last.txt %NF%>nul
goto end

:print
if %linecount% LSS %LN% echo %*>>top.txt
goto :eof

:dec
set /a %1=%1-1
goto :eof

:inc
set /a %1=%1+1
goto :eof

:end


This is using no external utilities. Works under Windows XP.

Thoughts?

Tidied version:
CODE
@Echo off&Setlocal
:: Existing Filename [to add text to]
Set "EF=existing.txt"
:: Line Number [to insert string]
Set "LN=3"
:: Text String [to add]
Set "TS=Text string added!"
:: New Filename [as updated document]
Set "NF=NewFile.ext
::Type Nul>%NF%
Set LC=0
Echo/%TS%>_#$_2
For /f "delims=" %%# In (%EF%) Do (Set/a LC +=1&Call :PR_ %%#)
Set/a LN -=1
More +%LN% %EF%>_#$_3
Copy/b _#$_1+_#$_2+_#$_3 %NF%>Nul&&Del _#$_*
Goto :Eof
:PR_
If %LC% Lss %LN% Echo/%*>>_#$_1
Yzöwl
Superb GSM, I'm happy to leave your vbscript solution here to help show how much quicker it'll work than a batch only solution. Because it edits a stream as SED would but is built-in it deserves its place in this thread

I just thought I'd clarify for anyone interested that the expected output should be:
CODE
I am the first line of this document.
I once stated, "I am the second line".
Text string added!
I demand to stay put! I don't wish to move!

Do you wish to stop & start notepad, just start it, or neither? 
 
My email, <something@somedomain.ext>, is not working!


For the sake of keeping everything together, here's the SED and GAWK solutions
SED
CODE
@Echo off&Setlocal
:: Existing Filename [to add text to]
Set "EF=existing.txt"
:: Line Number [to insert string]
Set "LN=3"
:: Text String [to add]
Set "TS=Text string added!"
:: New Filename [as updated document]
Set "NF=NewFile.ext"
::Type Nul>%NF%
Set/a PL=LN-1
Sed -n 1,%PL%p %EF%>%NF%
Echo:%TS%>>%NF%
Sed -n %LN%,$p %EF%>>%NF%
GAWK
CODE
@Echo off&Setlocal
:: Existing Filename [to add text to]
Set "EF=existing.txt"
:: Line Number [to insert string]
Set "LN=3"
:: Text String [to add]
Set "TS=Text string added!"
:: New Filename [as updated document]
Set "NF=NewFile.ext
::Type Nul>%NF%
Set/a PL=LN-1
Gawk "{print;if(NR==%PL%)print"""%TS%"""}" %EF%>%NF%


Congratulations Scr1ptW1zard, we have a working entry according to the original specification.

I have nothing but admiration for you for giving this a shot, was intrigued by your approach and love your use of the copy switch! I may be completely wrong but I have no recollection of seeing a script attempt this 'simple' task anywhere on the net and didn't expect anyone to take up the 'pointless' challenge. I'm however a little bit disappointed with one particular aspect; It seems as if it produces the output quicker than mine, the difference isn't much but I'm sure that if I was adding a line to a large file mine would be a lot slower.

Now for the kicker, to show how different content can really affect your work, change the insert line number to 13 and change the existing.txt to:
CODE
Column 1 | Column 2

A variable is enclosed in percent signs: %var1%

10% of 42 = 5% of 21
My email, <something@somedomain.ext>, is not working!
 
Do you wish to stop & start notepad, just start it, or neither? 

I demand to stay put! I don't wish to move!
I stated, "I am in the middle of something".


I stated, "I am in the middle of something".
I demand to stay put! I don't wish to move!

Do you wish to stop & start notepad, just start it, or neither? 
 
My email, <something@somedomain.ext>, is not working!
10% of 42 = 5% of 21

A variable is enclosed in percent signs: %var1%

Column 1 | Column 2
Lines
NotesThis file is mirrored, first and last lines say <TAB>Column 1<TAB>|<TAB>Column 2
Lines 7 and 18 contain a single space
Lines 8 and 17 end with a trailing space
Now start pulling your hair out!

BTW, my solution adds just a single line to my 'starter' script, which I split, for beautifying reasons, into three

P.S I'm going to edit/append posts etc. in order not to completely ruin the original intent of the topic and try to keep only the better attempts here!
Scr1ptW1zard
QUOTE (Yzöwl @ Jun 13 2008, 05:59 PM) *
Congratulations Scr1ptW1zard, we have a working entry according to the original specification.

I have nothing but admiration for you for giving this a shot, was intrigued by your approach and love your use of the copy switch! I may be completely wrong but I have no recollection of seeing a script attempt this 'simple' task anywhere on the net and didn't expect anyone to take up the 'pointless' challenge. I'm however a little bit disappointed with one particular aspect; It seems as if it produces the output quicker than mine, the difference isn't much but I'm sure that if I was adding a line to a large file mine would be a lot slower.


Wow! Thank you for the compliment Yzöwl! rolleyes.gif
This was one of those challenges that I just could not stop working on. So many times I was getting close but missing one special character. I ended up scraping everything and starting from scratch today with a completely different thought process. Methodically stepping through what needed to be done, made me see a straight-forward solution.

Thank you very much for your comments. I am glad to contribute to this fine community.

<Edit> : Updated solution for changed parameters

I think this should handle all the requirements:

CODE

@echo off

:: Existing Filename [to add text to]
Set "EF=existing.txt"
:: Line Number [to insert string]
Set "LN=13"
:: Text String [to add]
Set "TS=Text string added!"
:: New Filename [as updated document]
Set "NF=NewFile.ext"

if exist %NF% del %NF%
call :_dec LN
for /L %%# in (1,1,%LN%) do (
call :_doit %%#
)
echo %TS%>>%NF%
more +%LN% %EF%>>%NF%
goto _end

:_dec
set /a %1 -=1
goto :eof

:_doit
findstr /N /R "." %EF%|findstr /B /C:"%1:">nul
if errorlevel 1 (
echo.>>%NF%
) else (
for /f "tokens=1,* delims=: " %%a in ('findstr /N /R "." %EF%^|findstr /B /C:"%1:"') do (
if [%%b] EQU [] (
echo. >>%NF%
) else (
echo %%b>>%NF%
)
)
)
goto :eof

:_end



A bit slower as the line number for the insertion is increased. I tested inserting the line at each line of the file as well as lines that do not exist. When entering a line greater than the number of lines in the file, additional lines are added to reach the desired line.
</Edit>
Google Internet Forums Unattended CD/DVD Guide
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.