Batch file to output lines after string match, filename - windows

I have a directory of thousands of text files that begin with tape* (they're output files from an old Fortran program) and I need to extract 4 lines from each file as well as the filename that they were extracted from. The 4 lines begin 4 lines down from a predictable string, but we can use "Header" for this example:
tape1:
First line
...
Header
Trash1
Trash2
Trash3
Data1
Data2
Data3
Data4
...
I don't care about anything before or after those 4 data lines, but I also want the filename (i.e. "tape1") output after each Data line, like so:
Data1 tape1
Data2 tape1
Data3 tape1
Data4 tape1
Data5 tape2
Data6 tape2
...
Any thoughts on an easy Windows batch file to do this on all tape* files in a directory?

#echo off
setlocal EnableDelayedExpansion
for /F "tokens=1,2 delims=:" %%a in ('findstr /N "Header" tape*') do (
(for /L %%i in (-2,1,%%b) do set /P "="
for /L %%i in (1,1,4) do set /P "line=" & echo !line! %%a
) < "%%a"
)

#echo off
cls
rem get a list of file names sorted alphabetically by name
dir /b tape* /ON>.\Files.txt
rem delete any existing output from any previous run
if exist .\FoundData.txt del .\FoundData.txt
SET DataFileName=
SET LineData=
SET FoundData=
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F %%A IN (.\Files.txt) DO (
SET DataFileName=%%A
FOR /F "tokens=1,2* " %%B IN (!DataFileName!) DO (
rem use the following line to get just the first word on the line
rem SET LineData=%%B
rem use the following line to get the entire line
SET LineData=%%B %%C %%D
rem determine if the line contains "DATA" (case insensitive) and if so capture it
if "%FoundData%"=="" ( ECHO !LineData!|FIND /I "DATA">Nul && (SET FoundData=!LineData! ) || (SET FoundData=) )
rem if the line contained the data we want output it to the output file
IF NOT "!FoundData!"=="" (
(ECHO !FoundData! !DataFileName!>>.\FoundData.txt)
)
)
SET LineData=
SET FoundData=
)
set DataFileName=
)
ENDLOCAL
if not exist .\FoundData.txt echo No data found>.\FoundData.txt
start notepad .\FoundData.txt

You could try the following:
#echo off
for %%F in (".\tape*.txt") do (
for /F "delims=:" %%N in ('findstr /N /X /C:"Header" "%%~F"') do (
call :SUB "%%~F" %%N
)
)
exit /B
:SUB
set /A "SKIP=%~2+3"
for /F "skip=%SKIP% usebackq delims=" %%L in ("%~1") do (
echo(%%L %~n1
)
exit /B
Here is an alternative approach:
#echo off
for %%F in (".\tape*.txt") do (
for /F %%C in ('^< "%%~F" find /C /V ""') do (
set /A "POS=0" & set "NAME=%%~nF"
< "%%~F" (
setlocal EnableDelayedExpansion
for /L %%I in (1,1,%%C) do (
set "LINE=" & set /P LINE=""
if "!LINE!"=="Header" (
set /A "POS=%%I+3"
)
if !POS! GTR 0 if %%I GTR !POS! (
echo(!LINE! !NAME!
)
)
endlocal
)
)
)

Related

Batch - get content between two strings

I have string like this
<AdaptationSet maxHeight="576" maxWidth="1024" mimeType="video/mp4" id="0" segmentAlignment="true" startWithSAP="1">
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed" cenc:default_KID="bcf950eb-a062-5b0d-b1f2-fed53f20ba10">
<cenc:pssh>AAAATHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAACwiJGFlNWU5NTk4LWU5ODktNWM1Ny1iOTk2LTg3OTA4NWIyYzUxNUjj3JWbBg==</cenc:pssh>
</ContentProtection>
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="bcf950eb-a062-5b0d-b1f2-fed53f20ba10" />
<SegmentTemplate duration="6000" initialization="$RepresentationID$/video/init.mp4" media="$RepresentationID$_184201/segment_$Number$.m4s" startNumber="0" timescale="1000" />
<Representation bandwidth="247600" codecs="avc1.64001F" height="144" width="256" id="ae5e9598-e989-5c57-b996-879085b2c515-0_video_frag_auto.idx~video_frag_auto~481" scanType="progressive" />
I want to get output like below and put it into a variable.
ae5e9598-e989-5c57-b996-879085b2c515
Note that there is already id="0" in the first line and I want to extract value of id partially for the last line.
Is there an easy way to do this in batch?
If you must use batch, here's one example to get started. This extracts all values id from file ooo.txt that contains your string.
#echo off
setlocal enabledelayedexpansion
set x=0
for /f "eol=> tokens=* usebackq delims= " %%i in (`type ooo.txt`) do (
set x=0
set XXX=XXX
for %%I in (%%i) do (
if "%%I"=="id" (
set x=1
) else (
if !x! EQU 1 (
set x=0
set XXX=%%I
)
)
)
set XXX=!XXX:"=!
if not "!XXX!"=="XXX" (
set XXX=!XXX:"=!
rem echo !XXX!
call :enumerate !XXX! YYY
echo !YYY!
)
)
goto :eof
:enumerate
set pos=0
set Y=%1
set result=
set part=
:countchar
if not "!Y:~%pos%,1!"=="" (
set /a pos=pos+1
if "!Y:~%pos%,1!"=="-" (
set result=!result!!part!
set part=
)
set part=!part!!Y:~%pos%,1!
goto :countchar
)
set %~2=!result!
exit/b
:eof
endlocal
This outputs
ae5e9598-e989-5c57-b996-879085b2c515
and, within the loop, stores each id in variable YYY (although the first one is empty).
This assumes you want to keep everything up to but not including the last hyphen -.
Here's a 'for fun' example, which, as you've provided no code yourself, will not be modified post answer, and no support, or explanation, will be undertaken either.
#For /F Delims^= %%G In ('%__AppDir__%findstr.exe /i "id=\"[a-e0123456789]*-[a-e0123456789]*-[a-e0123456789]*-[a-e0123456789]*-[a-e0123456789]*-" "xmlfile.mpd"'
) Do #Set "}=%%G" & SetLocal EnableDelayedExpansion & For /F UseBackTokens^=2-6Delims^=-^" %%H In ('!}:* id^=^"^=!') Do #Endlocal & Set "id=%%H-%%I-%%J-%%K-%%L"
#(Set id) 2>NUL & Pause
You will probably want to change the source filename from xmlfile.mpd, and can optionally remove the last line, which was included just to allow you to see if it worked!
#ECHO OFF
SETLOCAL
rem The following settings for the source directory, destination directory, target directory,
rem batch directory, filenames, output filename and temporary filename [if shown] are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "filename1=%sourcedir%\q65892027.txt"
SET "capture="
SET "captured="
FOR /f "usebackqdelims=" %%b IN ("%filename1%") DO (
FOR %%c IN (%%b) DO (
IF /i "%%~c"=="scantype" SET "capture="&IF DEFINED captured GOTO done
IF DEFINED capture SET "captured=%%~c"
IF /i "%%~c"=="id" SET "capture=Y"
)
)
:done
ECHO captured "%captured%"
GOTO :EOF
setlocal enabledelayedexpansion
echo:
set "td=%~dp0"
set "pattern= id="
set "id=id"
call:getPatternLength "!id!" plen
set /a "slen=!plen!-1"
set "opt=tokens=1,2,* delims=<"
for /f "tokens=* delims=" %%z in (' type "!td!usedata\id.txt"^| findstr /c:"!pattern!" ') do (
for /f "%opt%" %%b in ("%%z") do (
for /f "tokens=* delims=" %%y in ('echo/%%b^|findstr /v [0-9][a-z]') do (
set "bempty=true"
call:findit "%%c" "!id!" strfound
)
if not defined bempty call:findit "%%b" "!id!" strfound
set "strfound=!strfound:"=!"
if defined strfound (
call:handlefound "!strfound!" result
if defined result (echo Finally: !result! & exit /b 0)
)
)
)
:end
endlocal
exit /b 0
:getPatternLength
set "str=%~1"
set /a "count=0"
:next
for /f "tokens=* delims=" %%z in ('echo/!str!') do (
set /a "count+=1"
set "str=!str:~1!"
if not "!str!"=="" goto:next
)
set "%2=!count!"
if /i "%0"==":getPatternLength" (exit /b 0)
:handlefound
set "str=%~1"
for /f "tokens=* delims=" %%a in ('echo/!str!^| findstr [a-z]') do (
:notyet
for /f "tokens=1,2,* delims=-" %%d in ("!str!") do (
for /f "tokens=* delims=" %%g in ('echo/%%e^|findstr "_"') do (
set "res=!res!-%%d"
set "%2=!res!"
exit /b 0
)
if not defined res ( set "res=%%d" ) else ( set "res=!res!-%%d")
set "str=%%e-%%f" & goto:notyet
)
)
echo Not the right line.. next.
exit /b 1
:findit
set "str=%~1"
set "find=%~2"
set "opts=tokens=1,* delims= "
set "opts2=tokens=1,* delims=="
:nexttoken
for /f "%opts%" %%m in ("!str!") do (
for /f "%opts2%" %%o in ("%%m") do (
if "%%o"=="!find!" (
set "%3=%%p"
if "%0"==":findit" exit /b 0
)
set "str=%%n" & goto:nexttoken
)
)
exit /b 1

Batch file : Encrypted opt out repeats it self for every file

Hi and thanks for answer, so my batch file that is intended to encrypt certain files with certain extensions. So there is my code:
#echo off
setlocal EnableDelayedExpansion
set "Alphabet=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
set "lowCase=abcdefghijklmnopqrstuvwxyz"
:a offset "input string" outVar=
setlocal DisableDelayedExpansion
set "inString=%~2"
set maxLen=80
set offset=11
set fname=%random%.%random%.%random%.%random%
setlocal EnableDelayedExpansion
(
for /f "tokens=*" %%X in ('dir /b /s *.encodeme') do (
FOR /f "delims=" %%a IN ('findstr /v /L /i /b /c:"INDEX?" "%%X"') DO (
SET "line=%%a"
call :A %offset% "!line!" a=
echo !a!
type %fname% > %%X
del /Q %fname%
)
)
)>"%fname%"
:A offset "input string" outVar=
setlocal DisableDelayedExpansion
set "inString=%~2"
setlocal EnableDelayedExpansion
for /L %%i in (0,1,61) do (
set /A "i=(%%i + %1) %% 62"
set c["!Alphabet:~%%i,1!"]=!i!
)
set "outVar="
for /L %%i in (0,1,%maxLen%) do (
set "char=!inString:~%%i,1!"
if defined char (
for /F "delims=" %%c in ("!char!") do (
if defined c["%%c"] (
set j=!c["%%c"]!
if "!lowCase:%%c=%%c!" neq "%lowCase%" set /A "j-=26"
for /F %%j in ("!j!") do set "outVar=!outVar!!Alphabet:~%%j,1!"
) else (
set "outVar=!outVar!!char!"
)
)
)
)
(
endlocal
for /F "delims=" %%a in ("%outVar:!=^!%") do endlocal & set "%3=%%a"
)
I have problem with the script that it will repeat its previous encrypted results.
For example, first encrypted file content is ok : Er6HGFJFrq6FJpFr6
Second example file content is repeated from previous on :
Er6HGFJFrq6FJpFr6
C:\Users\HP\Desktop\16383.29528.16703.12516
n6GJp6GJp7GF6
I want it to be just :
n6GJp6GJp7GF6
Sorry for my English, if you could help me, thank you!

Batch variable store result from command

It seems for me a very simple question, however I am struggling a lot with this and don't find an answer yet.
My aim is to count occurences of a specific string in a file.
I do or try to do this using following command:
for /f "tokens=2 delims=;" %%a in ('path to file with searchstring') do (
set count=('path to file I am searching in' find /c "%%a")
if !count! NEQ 0 echo !count!
)
Seems straightforward for me however the second line seems to be wrong as the script exits.
I want to save the result of findin a var because I only wants to outpout Nonzero resutls.
Here's an example batch-file using findstr, for better word matching, (It uses the filenames from your previous question):
#(For /F "UseBackQTokens=2Delims=;" %%G In ("classID.txt")Do #(Set "count=0"
For /F %%H In ('^""%__AppDir__%findstr.exe" /IN "\<%%G\>" "trc.txt"^"'
)Do #(Set /A count+=1)&SetLocal EnableDelayedExpansion
If !count! Gtr 0 (Echo %%G: !count!)&Endlocal))&Pause
Here it is fully parenthesized over multiple lines for you to better understand:
#Echo Off
For /F "UseBackQ Tokens=2 Delims=;" %%G In (
"classID.txt"
) Do (
Set "count=0"
For /F %%H In (
'^""%__AppDir__%findstr.exe" /I /N "\<%%G\>" "trc.txt"^"'
) Do (
Set /A count +=1
)
SetLocal EnableDelayedExpansion
If !count! Gtr 0 (
Echo %%G: !count!
)
Endlocal
)
Pause
And a fully parenthesized example of it outputting the results to a file named results.txt:
#Echo Off
(
For /F "UseBackQ Tokens=2 Delims=;" %%G In (
"classID.txt"
) Do (
Set "count=0"
For /F %%H In (
'^""%__AppDir__%findstr.exe" /IN "\<%%G\>" "trc.txt"^"'
) Do (
Set /A count +=1
)
SetLocal EnableDelayedExpansion
If !count! Gtr 0 (
Echo %%G: !count!
)
Endlocal
)
)>"results.txt"

How to use Windows batch for bicirculation

two files 1.txt 2.txt
1.txt
a2441
b4321
p8763
2.txt
Apple
banana
peach
I want to generated content in 12.bat
ren a2441 Apple
ren b4321 banana
ren p8763 peach
I try to write like this but failed
#echo on
for /f %%a in (1.txt) do (
for /f %%b in (2.txt ) do (
ren %%a %%b>>12.bat
)
)
pause
How can I achieve my desired results? help me,thks
It is not so straightforward. You'll need to skip increasing amount of lines in the inner loop , but because of the FOR parsing you'll need additional subroutine call.And if there are empty lined they need to be stripped with findstr for more accurate skipping of the lines. Also skip argument in FOR does not accept 0 so also an if is needed.
#echo off
setlocal ENABLEDELAYEDEXPANSION
set /a s=0
for /f "tokens=* delims=" %%a in (1.txt) do (
call :inner !s!
echo ren %%a !second!
set /a s=s+1
)
endlocal
pause
exit /b
:inner
set "second="
if %1==0 (
for /f "tokens=* delims=" %%b in ('findstr /r "[a-zA-Z]" "2.txt"') do (
if not defined second set "second=%%b"
)
) else (
for /f "skip=%1 tokens=* delims=" %%b in ('findstr /r "[a-zA-Z]" "2.txt"' ) do (
if not defined second set "second=%%b"
)
)
The problem with anidated loops is that for each line of the outer file/loop all the lines of the inner file/loop are processed.
One simple solution is to number the lines of both files and only generate the output line when both numbers match. Quick and dirty:
#echo off
setlocal enableextensions disabledelayedexpansion
>"12.bat" (
for /f "tokens=1,* delims=:" %%a in ('findstr /n "^" 1.txt') do (
for /f "tokens=1,* delims=:" %%c in ('findstr /n "^" 2.txt') do (
if %%a==%%c (
echo ren %%b %%d
)
))
)
This code just uses findstr to generate line numbers (/n) for each of the input files, and using the delims and tokens clauses of the for /f command to separate them from the original line contents (note: if the lines could start with a colon, more code is needed). If the line number in first file matches the line number in second file the command is echoed (there is a active output redirection to the final file)
Another option is to assign each file to a input stream and to read them using set /p operations from each of the streams
#echo off
setlocal enableextensions disabledelayedexpansion
call :processFiles 9<"1.txt" 8<"2.txt" >"12.bat"
goto :eof
:processFiles
<&9 set /p f1= || goto :eof
<&8 set /p f2= || goto :eof
echo ren %f1% %f2%
goto :processFiles
In the call to the subroutine we assign each file to a stream. Inside the subroutine each stream is read with set /p (note: set /p can not read lines longer than 1021 characters)

for command is executed only for the first value when a label is inside

I have the script
for /f "delims=" %%i in ('dir "%folder%*.txt" /b /s') do (
set s=%%i
set s=!s:%folder%=!
set new_s=!s:\=!
if "x!new_s!" NEQ "x!s!" (
:ProcessListSource
For /f "tokens=1* delims=\" %%A in ("!s!") do (
if "%%A" NEQ "" (
if "!Folder1!" NEQ "" (
Set Folder1=!Folder1!\!Name!
)else (
Set Folder1=!Name!
)
Set Name=%%A
)
if "%%B" NEQ "" (
set s=%%B
goto :ProcessListSource
)
)
echo Folder is: !Folder1!
echo Name is: !Name!
echo ---------------------
) else (
echo Not a folder !s!
)
)
but it does not work as I would have expected:
The first for is executed only once and also the last echo is printed on the screen.
Given a folder I need the files from subfolders without the given folder and than split them into the folder and file
Ex: folder=C:\test
The for would give me the file C:\test\test1\test2\t.txt
And I need test1\test2 and t.txt
GOTO breaks your FOR /F \ IF context and they can be executed only once.
More simple example:
#echo off
for /l %%S in (1=1=5) do (
echo %%S
goto :inner_label
rem
:inner_label
rem
)
This will print only 1 . Do you really need the GOTO here?
When the parser reads your code, all the code inside your for loop is "considered" as only one command that is readed, parsed and executed. As stated in the npocmaka answer, any goto call takes you out of this "line" of code, ending the process of the for loop.
This is a alternative. Use pushd + xcopy /l /s commands to generate a list of the relative paths of the files.
#echo off
setlocal enableextensions disabledelayedexpansion
set "folder=%cd%"
pushd "%folder%"
for /f "delims=" %%a in ('xcopy /l /s /y * "%temp%"^|findstr /vbr /c:"[0-9]"'
) do for /f "delims=: tokens=1,*" %%b in ("%%~a") do (
echo [%%c] [%%~nxa]
)
popd

Resources