I have a lot of .txt files which has information like this:
randomtext[IMPORTANTTEXT]morerandomtext
How can I cut out the important text without the braces and maybe overwrite the original .txt in batch?
The following will also do multiple instances in the same line. I'll leave it to you to change it to use a path for the *.txt files.
Test data:
Test1.txt
randomtext[IMPORTANTTEXT1a]morerandomtext
randomtext[IMPORTANTTEXT1b]morerandomtext
Test2.txt
randomtext[IMPORTANTTEXT2]morerandomtext
randomtext[IMPORTANTTEXT2a]morerandomtext randomtext[IMPORTANTTEXT2b]morerandomtext
Batch file:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
rem For each text file in the current directory...
for /f "tokens=*" %%F in ('dir /b *.txt') do (
set FileSpec=%%F
rem For each line of text in the file that has at least one [
for /f "tokens=1,* delims=[" %%a in (!FileSpec!) do (
rem This line of text has a [ so get the important text. %%a[%%b
rem below passes the entire line of text.
call :FindImportantText %%a[%%b
)
)
ENDLOCAL
pause
exit /b
:FindImportantText
for /f "tokens=1,* delims=[" %%c in ("%*") do (
rem The "%*" above is the entire line of text even if it contains
rem spaces which would normally delimit the line into pieces
if not "%%d"=="" (
rem There is a [ and text following the [. %%d is the portion
rem following the [.
rem so find the ending ]
for /f "tokens=1,* delims=]" %%e in ("%%d") do (
if not "%%f"=="" (
rem We have an ending ] so show it
echo ImportantText in !FileSpec!=%%e
rem Try again with the remaining portion of the line
call :FindImportantText %%f
)
)
)
)
exit /b
This will filter out the parts between the first pair of brackets:
for /f "tokens=2 delims=[]" %%a in ('type %1') do echo.%%a>>%2
If there are lines without any "important parts", you can skip them with findstr or by checking whether the output is empty:
for /f "tokens=2 delims=[]" %%a in ('type %1') do if "%%a" neq "" echo.%%a>>%2
To process all .txt files in the current directory, call the loop with another loop:
#echo off
for %%a in (*.txt) do call :brekkies "%%a" "%%~na_out.txt"&echo.%%a
echo.done.
exit /b
:brekkies
for /f "tokens=2 delims=[]" %%a in ('type %1') do if "%%a" neq "" echo.%%a>>%2
Files are going to be named "[name]_out.txt".
Related
I am trying to write a batch script that reads 18th line from a .log file and outputs the same. The .log file name varies each time. abc_XXXX.log where xxxx are process IDs. Below is the code I am trying to run to achieve this.
:Test1
set "xprvar=" for /F "skip=17 delims=" %%p in (abc*.log) do (echo %%p& goto
break)
:break
pause
goto END
set var=anyCommand doesn't work. It just sets the var to the literal string.
The usage of afor /f is the right way, just the variable assignment works different:
for /F "skip=17 delims=" %%p in ('dir /b abc*.log') do ( set "xprvar=%%p"& goto break )
There is also an option using FindStr
#Echo Off
For /F "Tokens=1-2* Delims=:" %%A In ('FindStr/N "^" "abc_*.log" 2^>Nul'
) Do If %%B Equ 18 Echo %%A:%%C
Pause
The above example Echoes the <filename>:<18th line content>, but there's no reason in the appropriate situation why you couldn't change that to read:
#Echo Off
For /F "Tokens=1-2* Delims=:" %%A In ('FindStr/N "^" "abc_*.log" 2^>Nul'
) Do If %%B Equ 18 Set "xprvar=%%C"
If there is more than one matching filename in the directory, the variable would be set to the content in the last file parsed.
#ECHO Off
SETLOCAL
FOR %%f IN (abc*.log) DO (
SET "reported="
FOR /f "skip=17delims=" %%p IN (%%f) DO IF NOT DEFINED reported (
ECHO %%p
SET "reported=Y"
)
)
Assign each filename in turn to %%f.
For each filename found, clear the reported flag then read the file, skipping the first 17 lines. echo the 18th line and set the reported flag so that the remainder of the lines are not echoed.
I have a series of text files each named the same in sub-folders of a certain directory
ac.txt files have the following structure :
---
some text
---
[lights]
---
some text
---
[GetEngineData]
---
some text
---
I want to get all those lines in between strings [lights] and [GetEngineData] (including those start [lights] and end [GetEngineData] lines) in one single output file called lights.txt with a blank space in between those coming from each text file.
I coded the following batch yet it is of no avail so far :
#ECHO OFF
for /r %%a in ('find /n "[lights]"^<(ac.txt) ') do set /a start=%%a
for /r %%a in ('find /n "[GeneralEngineData]"^<(ac.txt) ') do set /a end=%%a
(
for /r %%a in ('find /n /v ""^<(ac.txt) ') do (
IF %%a geq %start% IF %%f leq %end% ECHO(%%b
)
)>lights.txt
Here's a way to do it. Might not be the most efficient but it seems to do the job just fine. The code loops through all subfolders and picks up all .TXT files. It then parses each line of each file, marking the beginning/end of each block using the [lights] and [GeneralEngineData] tokens and then outputs everything to res.txt in the same folder where the batch file is stored.
#ECHO OFF
Setlocal EnableDelayedExpansion
if exist res.txt del res.txt
set inblock=0
for /r . %%a in (*.txt) do (
set fname=%%a
for /f "tokens=1* delims=]" %%b in ('type "!fname!" ^| find /n /v ""') do (
if /i *%%c*==*[lights]* set inblock=1
if !inblock!==1 (
if *%%c*==** (echo.) else (echo %%c)
if /i *%%c*==*[GetEngineData]* set inblock=0
)
)
echo.
) >> res.txt
set fname=
set inblock=
type res.txt
I have a folder with lots of .txt files with random names. Now I want to add a unique/ascending number to the end of each file in the folder. Example:
File 1 named "blah blah.txt with the content "hello world"
File 2 named "blah blah blah.txt with the content "hi hello world"
And after running the .bat file the files should be like:
File 1 named "blah blah.txt with the content "hello world1" <-- number "1" added
File 2 named "blah blah blah.txt with the content "hi hello world2" <-- number "2" added etc.
I wrote this line so far:
FOR %%a in (*.txt) do ECHO 1>> %%a
This adds a "1" to each .txt in the folder.
Theoretically I have to exchange the "1" with a variable
If all files have only one line, and no line begins with :, then
#echo off
for /f "tokens=1* delims=:" %%A in (
'dir /b /a-d *.txt ^|findstr /n "^"'
) do for /f "usebackq eol=: delims=" %%L in ("%%B") do (echo %%L%%A)>"%%B"
If dealing with multi-line files, and each line within a file is supposed to get the same number appended, then the following modification will work.
#echo off
for /f "tokens=1* delims=:" %%A in (
'dir /b /a-d *.txt ^|findstr /n "^"'
) do (
(for /f "usebackq eol=: delims=" %%L in ("%%B") do echo %%L%%A)>"%%B.new"
move /y "%%B.new" "%%B" >nul
)
I think this is what you want:
#echo off
setlocal enabledelayedexpansion
for /f "delims=" %%a in ('dir /b /a-d *.txt') do (
set /a inc+=1
for /f "usebackq delims=" %%b in ("%%~fa") do (
>"%%~fa" echo(%%b!inc!
)
)
For the indicate scenario, with only one line per file and a value added to the end of it
setlocal enableextensions disabledelayedexpansion
set "var=0"
for /r . %%a in (*.txt) do for /f "usebackq delims=" %%b in ("%%~fa") do (
set "line=%%b"
setlocal enabledelayedexpansion
>"%%~fa" echo(!line!!var!
endlocal
set /a "var+=1"
)
In a recursive search from the current folder and below (/r .), for each of the .txt files (%%a), for each of the lines in the file (%%b) echo the added variable after the readed line into the same file from it was read. In each loop the variable value is incremented by 1.
The setlocal/endlocal game inside the loop is intended to deal with special characters (!) inside the text in the file
I am looking to find a batch or VBS solution to strip out lines in a program generated text file with the extension of .trs.
In every .trs file created there is a line that contains the word 'labour'. I need every line after the line that contains the word labour to be deleted.
The .trs files are all stored in c:\export
I have searched for this but some of the commands were well over my head. Could anyone be so kind as to offer me a cut and paste open of the whole batch file, please.
I believe this is the code you are looking for (in a batch file) to remove all of the lines above the word "labour". Let me know if modifications need to be made to the code (such as if there are more than one instance of "labour" in the file).
#echo OFF
setLocal EnableDelayedExpansion
cd C:\export
for /f "delims=" %%I in ('findstr /inc:"labour" "test.trs"') do (
set /A"line=%%I"
)
set count=0
for /f "delims=" %%A in (test.trs) do (
If !count! GEQ %line% goto ExitLoop
echo %%A >>temp.txt
set /A count+=1
echo !count!
)
:ExitLoop
type temp.txt > test.trs
del temp.txt
endlocal
OUTPUT:
test.trs (BEFORE changes)
this
is
a
labour
test
of
the
results
test.trs (AFTER changes)
this
is
a
Here is an alternate method to process every .trs file in "C:\export":
#echo off
if not exist "C:\export\*.trs" goto :EOF
if exist "C:\export\queue.tmp" del /q "C:\export\queue.tmp"
for /f "tokens=*" %%A in ('dir /b "C:\export\*.trs"') do (
for /f "tokens=1,2 delims=:" %%B in ('findstr /inc:"labour" "C:\export\%%A" ^| findstr /n .*') do if "%%B" equ "1" set LineNumber=%%C
for /f "tokens=1* delims=:" %%D in ('findstr /n .* "C:\export\%%A"') do if %%D lss %LineNumber% echo.%%E>>"C:\export\queue.tmp"
move /y "C:\export\queue.tmp" "C:\export\%%A">NUL
)
First, I do some error checking to avoid things that would break the script. Next, I pull a list of .trs files stored in C:\export, and loop through each file.
I use 'findstr /inc:"labour" "C:\export\%%A"' to get the line number where "labour" is found in the current file, then pipe it into 'findstr /n .*' to number the results in case more than one match is found.
I then use a for loop with "tokens=1,2 delims=:" to find the first result (if "%%B" equ "1") and store the line number (set LineNumber=%%C).
Next, I use 'findstr /n .* "C:\export\%%A"' to read every line of the file, "tokens=1* delims=:" to separate out the line numbers again, then copy all the data to a temp file until %LineNumber% has been reached. This method of reading the file (using findstr and numbering the lines) also ensures that no blank lines will be skipped by the for loop.
Finally, I replace the original file with the temp file, then loop through to the next file.
I tried to keep the above code as slimmed down as possible. Here is the same script with formatting, comments, visual feedback, and user-definable variables:
#echo off
::Set user-defined Variables
set FilePath=C:\export
set FileType=*.trs
set Keyword=labour
::Check for files to process and exit if none are found
if not exist "%FilePath%\%FileType%" echo Error. No files to process.&goto :EOF
::Delete temp file if one already exists
if exist "%FilePath%\queue.tmp" del /q "%FilePath%\queue.tmp"
::List all files in the above specified destination, then process them one at a time
for /f "tokens=*" %%A in ('dir /b "%FilePath%\%FileType%"') do (
::Echo the text without a line feed (so that "Done" ends up on the same line)
set /p NUL=Processing file "C:\export\%%A"... <NUL
::Search the current file for the specified keyword, and store the line number in a variable
for /f "tokens=1,2 delims=:" %%B in ('findstr /inc:"%Keyword%" "%FilePath%\%%A" ^| findstr /n .*') do (
if "%%B" equ "1" set LineNumber=%%C
)>NUL
::Output all data from the current file to a temporary file, until the line number found above has been reached
for /f "tokens=1* delims=:" %%D in ('findstr /n .* "%FilePath%\%%A"') do (
if %%D lss %LineNumber% echo.%%E>>"%FilePath%\queue.tmp"
)>NUL
::Replace the current file with the processed data from the temp file
move /y "%FilePath%\queue.tmp" "%FilePath%\%%A">NUL
echo Done.
)
How do I make this grab the token from the first line ONLY in .txt file instead of looping through every line. I want %%m to be assigned to the 3rd token on line one only then stop.
#echo off
FOR %%A IN (.\xdrive\*.txt) DO (
FOR /F "usebackq tokens=3 delims=," %%m IN ("%%A") DO (
IF "%%m" == "F01" (xcopy /Y "%%A" .\Outbound)
pause
)
)
pause
set /p can be used to read the first line, and then you can use a FOR /F loop to get the third token
setlocal EnableDelayedExpansion
FOR %%A IN (%1) DO (
<%%A set /p firstline=
FOR /F "tokens=3 delims=," %%m IN ("!firstline!") DO (
echo %%m
)
)
Without see the eg files and knowing exactly what you're trying to do I can't test this, but here's the listing of firstline.bat which should do what you're asking for :) At first I thought this needed to be more complicated than it is... after your first if simply use a goto to exit the for structure after it's first call - problem solved?
#echo off
::: firstline.bat - Retrieve the first line from a series of files
::: usage: firstline $filespec
::: filespace - files to process (eg .\xdrive\*.txt)
if "%~1"=="" findstr "^:::" "%~f0"&GOTO:EOF
FOR %%A IN (%1) DO (
call :testfirst "%%A"
)
goto :eof
:testfirst
FOR /F "usebackq tokens=3 delims=," %%m IN (%1) DO (
IF "%%m" == "F01" (xcopy /Y %1 .\Outbound)
goto:eof
)
See this post, which shows how to mimic the gnu head utility using a dos batch file:
Windows batch command(s) to read first line from text file
untested
read first line tokens3
for /f "tokens=3 delims=," %%a in ('"findstr /n . %1|findstr /b 1:"') do set fltok3=%%a
echo(%fltok3%
Hackish =
#echo off
FOR %%A IN (.\xdrive\*.txt) DO (
FOR /F "usebackq tokens=3 delims=," %%m IN ("%%A") DO (
IF "%%m" == "F01" (xcopy /Y "%%A" .\Outbound)
GOTO:EOF
)
)
So all you're doing is escaping the loop after the first pass instead of continuing onto the next line.