Batch modifying text.txt before a specific word - batch-file

I have a file.txt where there are lines as
IF TANK T395 LEVEL ABOVE 4 THEN PUMP PFALDA395&T395 STATUS IS CLOSED
that I would like to transform in
IF TANK T395 LEVEL ABOVE 4
THEN PUMP PFALDA395&T395 STATUS IS CLOSED
I tried with this code.bat
#echo off
del "newfile.txt" 2>nul
(
for /f "eol=| usebackq for /f tokens=1,2,3,4,5,6,* delims= " %%a %%b %%c %%d %%e %%f %%g in ("oldfile.txt") do (
for /f %%h in ("%%g") do (
if /i "%%h"=="THEN" (
echo %%a %%b %%c %%d %%e %%f
echo. %%g
)
)
echo %%a %%b %%c %%d %%e %%f %%g
)
)>"newfile.txt"
I got a fast
%b non atteso (not waited)
What am I stumbling in?

just replace every <space>THEN<space> with <newline>THEN<space>:
#echo off
setlocal enabledelayedexpansion
REM Creating a Newline variable (the two blank lines are required!)
set NLM=^
set NL=^^^%NLM%%NLM%^%NLM%%NLM%
for /f "delims=" %%a in (t.txt) do (
set line=%%a
echo(!line: THEN =%NL%THEN !
)
(I took the creation of a NewLine from here)

You tried to specify variables for all tokens in the outer for command, but you must specify only the first one, which is %%a in your case; all the others (%%b, %%c,..., %%g) are defined implicitly via the tokens option (see also #Stephan's comment).
Besides that, your code outputs the original and the split line into the output file. Hence I inserted an else clause.
Finally, I implemented an additional condition: the code searches for IF as well now and splits therefore only lines which start with IF and contain THEN as the 7th token.
#echo off
del "newfile.txt" 2> nul
(
for /f "eol=| usebackq tokens=1,2,3,4,5,6,* delims= " %%a in ("oldfile.txt") do (
if /i "%%a"=="IF" (
for /f "eol=| tokens=1 delims= " %%h in ("%%g") do (
if /i "%%h"=="THEN" (
echo %%a %%b %%c %%d %%e %%f
echo %%g
) else (
echo %%a %%b %%c %%d %%e %%f %%g
)
)
) else (
echo %%a %%b %%c %%d %%e %%f %%g
)
)
) > "newfile.txt"
Edit:
The above solution can be simplified after following #Aacini's comment:
#echo off
del "newfile.txt" 2> nul
(
for /f "eol=| usebackq tokens=1-7* delims= " %%a in ("oldfile.txt") do (
if /i "%%a|%%g"=="IF|THEN" (
echo.%%a %%b %%c %%d %%e %%f
echo.%%g %%h
) else (
echo.%%a %%b %%c %%d %%e %%f %%g %%h
)
)
) > "newfile.txt"
Herein, only one for loop and one if clause is required.

Related

How to add a goto to a for loop

I am working on a script that edits files and I am building a choice goto menu.
The script itself works fine, it reads from a file name that has ( ) in it. So my files are saved like this (1) filename.txt, (2) filename.txt ....(100) filename.txt
the content of the file has "times": 125489, saved in it, the script removes the 100 from the file name and does this "times": 100,
This is a small part of my content for my txt files it has a 4 indent space per line I believe the format is Json
"aidr": 3.58,
"nlpr": 0.5,
"tafr": 0.5,
"titp": 0.5,
"trld": 0.0,
"tssp": 0.5,
"tssr": 0.5,
"ttup": 0.5,
"ttpp": 0.5,
"times": 125,
"Stamp": 125,
"ppiid": 649,
"otiid": 649,
"apcid": 9,
"orcid": 9,
"jpcns": 0,
"agpns": 0,
"opcns": 0,
"rppns": 0,
I recently found that when I merged all my single scripts together it slows down dramatically. Before the script processed 500 .txt files in 1 minute but now it takes 30 minutes.
My goal is to find a way to bring back the speed of this script.
I heard and read that adding a goto before and after the loop could make the script fast again.
#echo off
:Menu
ECHO ################################################################
echo.
ECHO 1 - Script 1
ECHO 2 - Script 2
ECHO 3 - Script 3
ECHO 4 - Script 4
ECHO 5 - Script 5
ECHO 100 - Script 100
echo.
set pass=
:: the choice command
set /p Mchoice=Make Your Choice:
::goto choices
goto=:%Mchoice%
goto %goto%
:1
#ECHO Off
setlocal ENABLEDELAYEDEXPANSION
set "ToReplace1="times": "
SET "sourcedir=New folder 1"
SET "destdir=New fodler 2"
FOR /f "delims=" %%q IN ('dir /b /a-d "%sourcedir%\(*)*.txt"') DO (
(
FOR /f "tokens=1 delims=()" %%j IN ("%%q") DO (
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" "%sourcedir%\%%q"') do (
set "line=%%b"
if defined line IF "%%b" neq "!line:times=!" CALL :Nums1 %%j
echo(!line!
)
)
)>"%destdir%\%%q"
)
GOTO :Menu
:Nums1
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%ToReplace1%%%s=%ToReplace1%!"
IF "%original%" neq "%line%" goto Nums1
set "line=!line:%ToReplace1%=%ToReplace1%%1!"
GOTO :eof
:2
#ECHO Off
setlocal ENABLEDELAYEDEXPANSION
set "ToReplace2="Stamp": "
SET "sourcedir=New folder 1"
SET "destdir=New fodler 2"
FOR /f "delims=" %%q IN ('dir /b /a-d "%sourcedir%\(*)*.txt"') DO (
(
FOR /f "tokens=1 delims=()" %%j IN ("%%q") DO (
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" "%sourcedir%\%%q"') do (
set "line=%%b"
if defined line IF "%%b" neq "!line:Stamp=!" CALL :Nums2 %%j
echo(!line!
)
)
)>"%destdir%\%%q"
)
GOTO :Menu
:Nums2
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%ToReplace2%%%s=%ToReplace2%!"
IF "%original%" neq "%line%" goto Nums1
set "line=!line:%ToReplace2%=%ToReplace2%%1!"
GOTO :eof
:15
#ECHO Off
setlocal ENABLEDELAYEDEXPANSION
cd /d "%~dp0"
set "ToReplace1="times": "
set "ToReplace2="Stamp": "
set "ToReplace3="jpcns": "
SET "sourcedir15=New folder 1"
SET "destdir15=New fodler 2"
FOR /f "delims=" %%q IN ('dir /b /s /a-d "%sourcedir15%\(*)*.txt"') DO (
SET "newdest=%%~dpq"
SET "newdest=!newdest:%sourcedir15%=%destdir15%!"
SET "newdest=!newdest:~0,-1!"
MD "!newdest!" 2>nul
(
FOR /f "tokens=1 delims=()" %%j IN ("%%~nxq") DO (
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" "%%q"') do (
set "line=%%b"
if defined line IF "%%b" neq "!line:times=!" CALL :Nums15 %%j
if defined line IF "%%b" neq "!line:Stamp=!" CALL :Nums15 %%j
if defined line IF "%%b" neq "!line:jpcns=!" CALL :Nums15 %%j
echo(!line!
)
)
)>"!newdest!\%%~nxq"
)
GOTO :Menu
:Nums15
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%ToReplace1%%%s=%ToReplace1%!"
FOR /L %%s IN (0,1,9) DO set "line=!line:%ToReplace2%%%s=%ToReplace2%!"
FOR /L %%s IN (0,1,9) DO set "line=!line:%ToReplace3%%%s=%ToReplace3%!"
IF "%original%" neq "%line%" goto Nums15
set "line=!line:%ToReplace1%=%ToReplace1%%1!"
set "line=!line:%ToReplace2%=%ToReplace2%%1!"
set "line=!line:%ToReplace3%=%ToReplace3%%1!"
GOTO :eof
I've done a few exercises on this problem, but I've been unable to locate anything that might result in a 30:1 speed difference.
This version
FOR /f "delims=" %%q IN ('dir /b /a-d "%sourcedir%\(*)*.txt"') DO (
(
FOR /f "tokens=1 delims=()" %%j IN ("%%q") DO (
for /F "tokens=1* delims=:" %%b in ('findstr /N "^" "%sourcedir%\%%q"') do (
set "line=%%c"
if defined line (
IF "%%c" equ "!line:times=!" (ECHO %%c) ELSE (
for /F "tokens=1* delims=:" %%v in ("%%c") do ECHO %%v: %%j,
)
) ELSE ECHO(
)
)
)>"%destdir%\%%q"
)
Seemed to be a little faster.
This:
FOR /f "delims=" %%q IN ('dir /b /a-d "%sourcedir%\(*)*.txt"') DO (
(
FOR /f "tokens=1 delims=()" %%j IN ("%%q") DO (
SET "skipover="
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" "%sourcedir%\%%q"') do (
IF DEFINED skipover (ECHO(%%b
) ELSE (
set "line=%%b"
if defined line IF "%%b" neq "!line:times=!" SET "skipover=y"&CALL :Nums1 %%j
echo(!line!
)
)
)
)>"%destdir%\%%q"
)
uses a Boolean variable skipover to bypass some of the processing once the target line has been found and manipulated - but it actually seemed slower.
This
FOR /f "delims=" %%q IN ('dir /b /a-d "%sourcedir%\(*)*.txt"') DO (
(
FOR /f "tokens=1 delims=()" %%j IN ("%%q") DO (
for /F "tokens=1* delims=:" %%b in ('findstr /N "^" "%sourcedir%\%%q"') do (
set "line=%%c"
if defined line (
IF "%%c" equ "!line:times=!" (ECHO %%c) ELSE (
for /F "tokens=1* delims=:" %%v in ("%%c") do ECHO %%v: %%j,
)
) ELSE ECHO(
)
)
)>"%destdir%\%%q"
)
was consistently a little faster than the original - it avoids the subroutine call.
And this:
FOR /f "delims=" %%q IN ('dir /b /a-d "%sourcedir%\(*)*.txt"') DO (
(
FOR /f "tokens=1 delims=()" %%j IN ("%%q") DO (
SET "skipover="
for /F "usebackqdelims=" %%e in ("%sourcedir%\%%q") do (
IF DEFINED skipover (ECHO/%%e
) ELSE (
set "line=%%e"
if defined line (
IF "%%e" equ "!line:times=!" (ECHO %%e
) ELSE (
SET "skipover=Y"
for /F "tokens=1* delims=:" %%v in ("%%e") do ECHO %%v: %%j,
)
) ELSE ECHO/
)
)
)
)>"%destdir%\%%q"
)
was consistently nearly twice as fast, using the skip-if-it's been-changed technique and avoiding findstr. It won't reproduce empty lines, though.
I also found that the position of the target in the source was signiificant. Using a 700-line version of the sample data, placing the target at the end was half-speed of placing it at the start of the file, so I was able to get nearly a 4:1 speed difference between the original and this last technique if the target was placed early in the source data (running 1,000 700-line files).
I presume that sub appeared in the original post by way of editing-out the irrelevant portions of the code, but it seemed to be reversed in sense, the way it was written...
--- based on version 3,
:: remove variables starting #
FOR /F "delims==" %%e In ('set # 2^>Nul') DO SET "%%e="
:: Read controls from file "%1"
FOR /f "usebackqtokens=1*" %%b IN ("%~1") DO (
SET "#%%b=%%c"
FINDSTR /x /i /L /c:":#%%b" <"%~f0" >NUL
IF ERRORLEVEL 1 ECHO LABEL ":#%%b" NOT found&SET "destdir="
)
IF NOT DEFINED destdir ECHO Required LABEL(s) NOT found &GOTO :eof
FOR /f "delims=" %%q IN ('dir /b /a-d "%sourcedir%\(*)*.txt"') DO (
(
rem %%q contains the name of the file to be processed
rem remove variables starting $
FOR /F "delims==" %%e In ('set $ 2^>Nul') DO SET "%%e="
rem extract filenumber if sourcefilename is (number)something
SET "filenumber="
FOR /f "tokens=1 delims=()" %%j IN ("%%q") DO SET "filenumber=%%j"
rem
rem now process the file
for /F "tokens=1* delims=:" %%b in ('findstr /N "^" "%sourcedir%\%%q"') do (
set "line=%%c"
if defined line (
rem if any #name is detected, take action
SET "processline=Y"
FOR /f "tokens=1,2delims=#=" %%u IN ('set #') DO IF DEFINED processline IF "%%c" neq "!line:%%u=!" (
SET "processline="
CALL :#%%u %%v
)
IF DEFINED processline ECHO %%c
) ELSE ECHO/
)
)>"%destdir%\%%q"
)
GOTO :eof
:#times
rem replace times value with filenumber
ECHO "times": %filenumber%,
GOTO :eof
:#titp
rem replace titp value with value read from file (%1)
ECHO "titp": %1,
GOTO :eof
:#tssp
rem put newz value before and zwen value after tssp value
ECHO "newz": whatever,
ECHO %line%
ECHO "zwen": revetahw,
GOTO :eof
:#trld
rem delete all trld values
GOTO :eof
:#tssr
rem replace the third and the fifth tssr value (I have multiples)
rem note that all $ variables are deleted FOR each file
SET /a $#tssr+=1
IF %$#tssr%==3 ECHO "tssr": thirdtime,&GOTO :eof
IF %$#tssr%==5 ECHO "tssr": fifthtime,&GOTO :eof
ECHO %line%
GOTO :eof
Using a control file contents
times #
titp jello
trld #
tssp #
tssr #
So - this is an attempt to obviate the repeated cloning of the file-processing logic.
First, I'm setting all variables that start # to nothing, un-defining them. That way, the remainder of the code knows that any variable starting # has not been inherited from elsewhere.
Next step : read the file to set up
#times=#
#titp=jello
#trld=#
#tssp=#
#tssr=#
The code then examines itself to make sure that subroutines :#times etc all exist and complains if they don't. destdir is simply a convenient non-empty variable used as a flag - we'll abort if the subroutines are missing, so no problem there.
Next - read the filenames. Obviously, the filemask may change depending on the selection made from the menu.
Then, for each file, kill all $ variables for the same reason as # but this time for each file to be processed.
Then set up variables to contain whatever data about the file is appropriate. Could be size, date, whatever - extract-parenethesised-number is shown. No harm in doing such things for all files, even if the data is not used for this particular menu selection.
Then process the file, detecting the keystrings from the # array. Call :#keystring if found, regurgitate line if not.
Each :# routine does what it does. A variety of possibilities is shown. Naturally, any particular routine could be controlled further by testing the selection made.
Setting the value assigned to #? to a value other than # will deliver that value to the :#? subroutine as parameters. Use them as you will - constants, whatever - just interpret the parameters delivered.
Naturally, you could set the # variables manually for particular menu selections instead of reading them from a file.
But - this is drifting way away from the timing problem - just adding more facilities (I'm a chronic implementor of bells and whistles) so I'd suggest to end discussion here.

IN ECHO statement how can i print all the columns without defining multiple output parameters

for /f " tokens=%i%-%j% delims=," %%a in (%input%) DO (
(ECHO %%a %%b %%c %%d %%e %%f %%g %%h %%i %%j)>>%output%
)
"delims=" will force no delimiter and use full string making each line %%a instead of each word, delimited by ,.
for /f "delims=" %%a in (%input%) DO ECHO %%a >>%output%
If you would like to get rid of the , simply replace it.
#echo off
setlocal enabledelayedexpansion
for /f "delims=" %%a in (%input%) DO ( set string=%%a
set string=!string: =,!
ECHO !string! >> %output%
)
endlocal
According to your comments, the following should do exactly, what you want: multiple spaces are reduced to one delimiter, no delimiters at the end of a line.
#echo off
setlocal enabledelayedexpansion
(for /f "delims=" %%a in (input.txt) do (
set "new="
for %%b in (%%a) do (
set "new=!new!,%%b"
)
echo !new:~1!
))>output.txt
Because your ? characters may be problematic with some solutions, the following may do what you require:
#Echo Off
Set "input=input.txt"
Set "output=output.txt"
Set "_="
(For /F "UseBackQ Delims=" %%A In ("%input%"
) Do Set "_="&Call :Sub %%A&Call Echo(%%_:~1%%)>"%output%"
If Not Defined _ Del "%output%"
Exit /B
:Sub
If "%1"=="" GoTo :EOF
Set "_=%_%,%1"
Shift&GoTo :Sub

Windows Batch File: First word of File Name as column 1

The below code from computing.net is almost completely useful but needs minor changes. I have no clue as to how this is working. Can someone please help ?
for %%a in (*.csv) do call :addId "%%~Na" "%%a"
goto :EOF
:addId
#echo off
for /f "usebackq delims=" %%b in (%2) do (
> #.csv echo ID,%%b
goto :next
)
:next
for /f "usebackq skip=1 delims=" %%b in (%2) do (
>> #.csv echo %~1,%%b
)
move #.csv %2
Need to remove the code that inserts a header "ID"
Use ONLY the first word of file NOT complete file name --- as column 1 value
Here, word means collection of alphabets that are separated by space. So 1st word will be collection of alphabets before 1st space.
Could someone please help ?
Use for /f parsing loops:
#echo off
for %%a in (*.csv) do (
echo Processing %%a
for /f "tokens=1 eol=*" %%b in ("%%~na") do (
set /p header=<"%%a"
call echo %%header%%
for /f "skip=1 usebackq delims=" %%c in ("%%a") do echo %%b,%%c
) >"%%a.new"
move /y "%%a.new" "%%a" >nul
)
pause
This will preserve the header line intact.
Can you try this? PLease let me know how it works.
setlocal enabledelayedexpansion
for %%a in (*.csv) do call :addId "%%~Na" "%%a"
goto :EOF
:addId
#echo off
for /f "usebackq delims=" %%b in (%2) do (
rem > #.csv echo ID,%%b
goto :next
)
:next
for /f "usebackq skip=1 delims=" %%b in (%2) do (
for /f "tokens=1 delims= " %%x in ("%~1") do set firstWord=%%x
>> #.csv echo !firstWord!,%%b
)
move #.csv %2

I can't get a variable of loop

I am trying to write a simple batch file
The script gets namefile for the file "dump" and I split the string, but i can't display the variable !!
for /r %%a in (dump\*) do (
set file=%%a
for /f %%i in ("%%a") do (
for /F "tokens=1 delims=-" %%d IN ("%%~ni") do set db=%%d
)
echo %db%
)
pause
Any ideas?
Thanks for your help.
try setting the setlocal ENABLEDELAYEDEXPANSION and swapping the var with exclamation marks instead, see below:
setlocal ENABLEDELAYEDEXPANSION
for /r %%a in (dump\*) do (
set file=%%a
for /f %%i in ("%%a") do (
for /F "tokens=1 delims=-" %%d IN ("%%~ni") do set db=%%d
)
echo !db!
)
pause

changing directory folder to all sub folders

Hello i have a batch script but i cant work out how to change the path to scan all subfolders within the directory.
In other words i dont want -
C:\Users\ally\Desktop\Documents\Table\CSV versions\2014\
but rather:
C:\Users\ally\Desktop\Documents\Table\CSV versions
as there are lots of different years of data in seperate folders.
Also to note within year folder there are month folders and within that there are the csv files.
#echo off
setlocal enabledelayedexpansion
set "target=C:\Users\ally\Desktop\Documents\All"
cd /d "C:\Users\ally\Desktop\Documents\Table\CSV versions\2014\"
for /L %%a in (101,1,148) do (
set num=%%a
del "%target%\-!num:~-2!.csv" 2>nul
>"%target%\-!num:~-2!.csv.txt" echo Type,angle,edge,Date,Frame,Sum,Mafe,Comp,Rim,Dose,Ell,Role
)
for %%a in (*.csv) do (
for /f "skip=1 usebackq delims=" %%b in ("%%a") do (
for /f "tokens=1,2 delims=-," %%c in ("%%b") do (
set "line=%%c"
if /i "!line:~0,2!"=="HH" >> "%target%\-%%d.csv.txt" echo %%b
)
)
)
ren "%target%\*.csv.txt" *.
pause
To process every folder under the All tree then you can use a for /d /r loop and pushd/popd to set the current folder.
This assumes that every folder has the files you want to process.
Test this on a copy of your data and change the folder to point to it.
You seem to be deleting .csv files, creating .csv.txt files and then trying to process *.csv in the lower loop. Should that be *.csv.txt ?
#echo off
setlocal enabledelayedexpansion
for /d /r "c:\Users\ally\Desktop\Documents\All" %%z in (*) do (
pushd "%%z"
for /L %%a in (101,1,148) do (
set num=%%a
del "-!num:~-2!.csv" 2>nul
>"-!num:~-2!.csv.txt" echo Type,angle,edge,Date,Frame,Sum,Mafe,Comp,Rim,Dose,Ell,Role
)
for %%a in (*.csv) do (
for /f "skip=1 usebackq delims=" %%b in ("%%a") do (
for /f "tokens=1,2 delims=-," %%c in ("%%b") do (
set "line=%%c"
if /i "!line:~0,2!"=="HH" >> "-%%d.csv.txt" echo %%b
)
)
)
ren "*.csv.txt" *.
popd
)
pause
Try adding another loop that will walk down the directory tree and if it finds a csv file, it will process it:
#echo off
setlocal enabledelayedexpansion
set "target=C:\Users\ally\Desktop\Documents\All"
for /f "tokens=1* delims=" %%D in ('dir /s /b /o:-n /a:d "C:\Users\ally\Desktop\Documents\Table\CSV versions"') do (
cd /d "%%~fD"
if exist *.csv (
for /L %%a in (101,1,148) do (
set num=%%a
del "%target%\-!num:~-2!.csv" 2>nul
>"%target%\-!num:~-2!.csv.txt" echo Type,angle,edge,Date,Frame,Sum,Mafe,Comp,Rim,Dose,Ell,Role
)
for %%a in (*.csv) do (
for /f "skip=1 usebackq delims=" %%b in ("%%a") do (
for /f "tokens=1,2 delims=-," %%c in ("%%b") do (
set "line=%%c"
if /i "!line:~0,2!"=="HH" >> "%target%\-%%d.csv.txt" echo %%b
)
)
)
ren "%target%\*.csv.txt" *.
)
)
pause
Explanation of the dir switches:
/s - Displays files in specified directory and all subdirectories.
/b - Uses bare format (no heading information or summary).
/o:in - Lists the files in reverse order
/a:d - Displays only folders
Explanation of the %%~fD: expands %A to a fully qualified path name (from for /?)

Resources