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
Related
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.
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
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.
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
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.