37} How can I insert a line in the middle of a file with a script?
The
logic of the task is simple. Get the first n lines, append your
line, and then get the rest of the lines starting from n+1.
The current task is easy with the additional tools
SED or
GAWK.
Say that you wish to insert something between the fourth and the
fifth line of your file. Below is how to do it:
@echo off
sed -n 1,4p myfile.txt>newfile.txt
echo Insert My added own line>>newfile.txt
sed -n 5,$p myfile.txt>>newfile.txt
With G(nu)AWK the solution is even simpler
gawk '{print;if(NR==4)print"My own added line"}' myfile.txt>newfile.txt
@echo off & setlocal enableextensions
rem The same with GnuWin32 gawk with less limitations (let's call it unxgawk)
unxgawk "{print;if(NR==4)print\"My own added line\"}" "My test file.txt" > "My new file.txt"
endlocal & goto :EOF
However, this can also be solved with pure script. The solution
below using subroutines is not the most concise one, but hopefully
it is instructive. In a FAQ like this clarity is preferred over
conciseness and sometimes even efficiency. Also note how as a
sideline it answers the questions "How do I get the first N lines of
my text file?" and "How do I get my text file's lines after line N".
(The latter could be answered with "skip=" as well.)
@echo off & setlocal enableextensions
:: Make a test file
for %%f in (myfile.txt mynew.txt) do if exist %%f del %%f
for %%f in (1 2 3 4 5 6 7 8 9) do echo This is line %%f>>myfile.txt
::
:: Insert where
set insertAfter=4
::
:: Initialize the linecount
set /a lineCount=0
::
:: Write the lines until and including the insertion point
for /f "delims=" %%r in ('type myfile.txt') do (
call :WriteUntilLine %%r>>mynew.txt
)
::
:: Insert new text
echo My added text>>mynew.txt
::
:: Start a new count
set /a lineCount=0
::
:: Write the lines until and including the insertion point
for /f "delims=" %%r in ('type myfile.txt') do (
call :WriteSinceLine %%r>>mynew.txt
)
::
:: Display the new file
type mynew.txt
::
:: Clean up
for %%f in (myfile.txt mynew.txt) do if exist %%f del %%f
endlocal & goto :EOF
::
:: ======================================================
:WriteUntilLine
set /a lineCount+=1
if %lineCount% LEQ %insertAfter% echo %*
goto :EOF
::
:: ======================================================
:WriteSinceLine
set /a lineCount+=1
if %lineCount% GTR %insertAfter% echo %*
goto :EOF
The output
D:\TEST>cmdfaq
This is line 1
This is line 2
This is line 3
This is line 4
My own added line
This is line 5
This is line 6
This is line 7
This is line 8
This is line 9
For a more concise, and also instructive alternative see
Google Groups Dec 18 2003, 11:14 am [
M]
For replacing a line instead of inserting, substitute
if %lineCount% LEQ %insertAfter% echo %*
with
if %lineCount% LSS %insertAfter% echo %*
Note the standard feature (or limitation, if you will) of the pure
script solution: If there are
empty lines
they will be omitted.
A Visual Basic Script (VBScript) aided command line script can be
used. It does not ignore the potential empty lines.
@echo off & setlocal enableextensions disabledelayedexpansion
::
:: Build a Visual Basic Script
set skip=
set vbs_=%temp%\slice.vbs
findstr "'%skip%VBS" "%~f0" > "%vbs_%"
::
:: Do the inserting
cscript //nologo "%vbs_%" 1 3 < "My test file.txt"
echo Inserted text after line 3!
cscript //nologo "%vbs_%" 4 99999 < "My test file.txt"
::
:: Clean up
for %%f in ("%vbs_%") do if exist %%f del %%f
endlocal & goto :EOF
'
'.......................................................
'The Visual Basic Script for "slice"
'
StartFromLineNumber=WScript.Arguments.Unnamed(0) 'VBS
EndAtLineNumber=WScript.Arguments.Unnamed(1) 'VBS
i = 0 'VBS
Do While Not WScript.StdIn.AtEndOfStream 'VBS
str = WScript.StdIn.ReadLine 'VBS
i = i + 1 'VBS
If (i >= CLng(StartFromLineNumber)) And (i <= CLng(EndAtLineNumber)) Then 'VBS
WScript.StdOut.WriteLine str 'VBS
End If 'VBS
Loop 'VBS
Assume the following LFN-type test file: "My test file.txt"
line 1
line 2 &()[]{}^=;!'+,`~
line 3 <>
line 4
line 6 Line 5 is empty!
line 7
line 8 &()[]{}^=;!'+,`~
line 9
The output will be
C:\_D\TEST>cmdfaq
line 1
line 2 &()[]{}^=;!'+,`~
line 3 <>
Inserted text after line 3!
line 4 ""
line 6 Line 5 is empty!
line 7
line 8 &()[]{}^=;!'+,`~
line 9
You might wish to see also the later
item #69
"How do I get the first, or the last, 400 lines of a file?".