151} Extract the lines of a text file from between two marker-lines?
> I have a text file that is like:
>
> date = OCT0606
> asdf
> sdaf
> asdfasdgsdgh
> asdfsdfasdg
> START-OF-DATA
> asdfasdfg
> asdfgdfgsfg
> sadfsdfgsa
> asdfgsdfg
> END-OF-DATA
> asdfgalsdkdfklmlkm
> asdfgasdfg
>
> I need to clear everything from this file except the data between
> the START-OF-DATA and END-OF-DATA using a batch file.
@echo off & setlocal enableextensions enabledelayedexpansion
set source=C:\_M\MyData.txt
set flagStart=
set flagEnd=
for /f %%a in ('type "%source%"') do (
echo %%a|find "START-OF-DATA">nul
if !errorlevel! EQU 0 set flagStart=true
echo %%a|find "END-OF-DATA">nul
if !errorlevel! EQU 0 set flagEnd=true
if defined flagStart if not defined FlagEnd (
echo %%a|find /v "START-OF-DATA"
)
)
endlocal & goto :EOF
Actually the lines
set flagStart=
set flagEnd=
are superfluous, but they depict the logic.
The output:
C:\_D\TEST>cmdfaq
asdfasdfg
asdfgdfgsfg
sadfsdfgsa
asdfgsdfg
Also as below. The first is inclusive, the second
exclusive
sed -n "/START-OF-DATA/,/END-OF-DATA/p" %source%
sed "1,/START-OF-DATA/d" %source%|sed "/END-OF-DATA/,$d"
The problem can also be solved with a command-line driven VBScript
filter. Note a crucial difference between the sed and the VBScript
solutions. If there several START-OF-DATA END-OF-DATA pairs within the
source files
the sed solution will extract all
the data in between, the VBScript solution only the first pair
encountered. - First an exclusive version, i.e. the
beginning and the ending marker are
excluded
from the output.
@echo off & setlocal enableextensions
::
:: Your parameters
set myfile_=C:\_M\MyData.txt
set cut1=START-OF-DATA
set cut2=END-OF-DATA
::
:: Build a Visual Basic Script
set vbs_=%temp%\tmp$$$.vbs
set skip=
findstr "'%skip%VBS" "%~f0" > "%vbs_%"
::
:: Run it with Microsoft Windows Script Host Version 5.6
cscript //nologo "%vbs_%" "%cut1%" "%cut2%" < "%myfile_%"
::
:: Clean up
for %%f in ("%vbs_%") do del %%f
endlocal & goto :EOF
'
'............................................
'The Visual Basic Script
'
set arg = WScript.Arguments 'VBS
startTrigger = arg(0) 'VBS
endTrigger = arg(1) 'VBS
'
startFound = False 'VBS
Do While Not WScript.StdIn.AtEndOfStream 'VBS
line = WScript.StdIn.ReadLine 'VBS
If InStr (1,line,endTrigger,vbTextCompare) > 0 Then Exit Do 'VBS
If startFound Then WScript.StdOut.WriteLine line 'VBS
If InStr (1,line,startTrigger,vbTextCompare) > 0 Then startFound = True 'VBS
Loop 'VBS
What if you wish to
include the beginning and
the ending line? (Unrelated, this snippet has a slightly different
setting of markers.)
@echo off & setlocal enableextensions
::
:: Your parameters
set myfile_=C:\_M\MyData.vcf
set cut1=BEGIN:VCARD
set cut2=END:VCARD
::
:: Build a Visual Basic Script (use your own temporary folder, if you have one)
set temp_=%temp%
if defined mytemp if exist "%mytemp%\" set temp_=%mytemp%
set vbs_=%temp_%\tmp$$$.vbs
set skip=
findstr "'%skip%VBS" "%~f0" > "%vbs_%"
::
:: Run it with Microsoft Windows Script Host Version 5.6
cscript //nologo "%vbs_%" "%cut1%" "%cut2%" < "%myfile_%"
::
:: Clean up
for %%f in ("%vbs_%") do del %%f
endlocal & goto :EOF
'
'............................................
'The Visual Basic Script
'
set arg = WScript.Arguments 'VBS
startTrigger = arg(0) 'VBS
endTrigger = arg(1) 'VBS
'Note the subtly different order and composition of the commands
startFound = False 'VBS
Do While Not WScript.StdIn.AtEndOfStream 'VBS
line = WScript.StdIn.ReadLine 'VBS
If InStr (1,line,startTrigger,vbTextCompare) > 0 Then startFound = True 'VBS
If InStr (1,line,endTrigger,vbTextCompare) > 0 Then 'VBS
WScript.StdOut.WriteLine line 'VBS
Exit Do 'VBS
End If 'VBS
If startFound Then WScript.StdOut.WriteLine line 'VBS
Loop 'VBS
VCF Cutter:
A real-life dilemma. I have from my Samsung Galaxy S4 Mini smartphone
its address book as one big exported VCF file with almost five hundred
names on it. How do I split that behemoth into individual Vcard files?
This time no command-line script purity, but whatever gets my task
done and saves my day. The answer lies in
G(nu)awk. After several hours of effort,
the solution was deceptively brief. Also note that because of the
compostion of the Contacts.vcf sourcefile it is sufficient to cut at
the "
BEGIN:VCARD" starting lines.
@echo off & setlocal enableextensions
set myfile_=C:\_M\Contacts.vcf
unxgawk "/BEGIN:VCARD/{x=++i}{a=\"000\"x}{p=length(a)}{a=substr(a,p-3,p)}{printf\"%%s\n\",$0>\"Vcard\"a\".vcf\"}" "%myfile_%"
endlocal & goto :EOF
Files produced:
Vcard0001.vcf Vcard0002.vcf Vcard0003.vcf Vcard0004.vcf Vcard0005.vcf
Vcard0006.vcf Vcard0007.vcf Vcard0008.vcf Vcard0009.vcf Vcard0010.vcf
Vcard0011.vcf Vcard0012.vcf Vcard0013.vcf Vcard0014.vcf Vcard0015.vcf
...
Vcard0451.vcf Vcard0452.vcf Vcard0453.vcf Vcard0454.vcf
The above can be rewritten in a more legible and script-like code as
@echo off & setlocal enableextensions
set temp_=%temp%
if defined mytemp if exist "%mytemp%\" set temp_=%mytemp%
set awkcmd_=%temp_%\tscmd$$$.awk
set myfile_=C:\_M\Contacts.vcf
> "%awkcmd_%" echo /BEGIN:VCARD/{x=++i}
>> "%awkcmd_%" echo {a="000"x}
>> "%awkcmd_%" echo {p=length(a)}
>> "%awkcmd_%" echo {a=substr(a,p-3,p)}
>> "%awkcmd_%" echo {printf "%%s\n",$0 ^> "Vcard"a".vcf"}
unxgawk -f "%awkcmd_%" "%myfile_%"
for %%f in ("%awkcmd_%") do if exist %%f del %%f
endlocal & goto :EOF