I am trying to modify a batch file created by somebody else, to add leading zeros depending on the number found on line 4 of the file. The actual filename is a concatenation of the name found on line 3, and the numbers on line 4. So if the first few lines are as follows:
3.1.19
-1
TEST
560
The file name would be v_TEST00560.TXT. As you can see, the total number of digits in the file name should be 5. If the number which appears on line 4 is 8 (see below), then:
3.1.19
-1
TEST
8
The file name will be v_TEST00008.txt.
The file I have is as follows:
#Echo Off
Setlocal EnableDelayedExpansion
REM File: rename5.bat
REM The script will look for and parse one (or more) input files
REM Input files can containrecords for one or more vessels.
REM This script assumes that each record starts with the "3.1.19" string.
REM %%%%%%%%%%%%%%%%%%%%%%% Configuration Section %%%%%%%%%%%%%%%%%%%%%%%
SET INPUT_DIR=C:\Files\RenameFileName\Input
SET OUTPUT_DIR=C:\Files\RenameFileName\Output
SET ARCHIVE_DIR=C:\Files\RenameFileName\Archive
SET TEMP_DIR=C:\Files\RenameFileName\tmp
SET INPUT_FILENAME=INTERFACE.TXT
SET REC=3.1.19
REM %%%%%%%%%%%%%%%%%%%%%%%%%%%% Checking Section %%%%%%%%%%%%%%%%%%%%%%%%%%%%
FOR /F "usebackq tokens=* eol= delims= " %%d IN (`date /t`) do SET RUNDATE=%%d
echo [%RUNDATE% %TIME%] Script starting...
IF NOT EXIST %INPUT_DIR% (
SET MESSAGE=Input directory not found.
goto END
)
IF NOT EXIST %OUTPUT_DIR% (
SET MESSAGE=Output directory not found.
goto END
)
IF NOT EXIST %ARCHIVE_DIR% (
SET MESSAGE=Archive directory not found.
goto END
)
IF NOT EXIST %TEMP_DIR% (
echo Temporary directory does not exit.
echo Creating %TEMP_DIR%
mkdir %TEMP_DIR%
)
REM %%%%%%%%%%%%%%%%%%%%%%%%% Main Processing %%%%%%%%%%%%%%%%%%%%%%%%%
dir %INPUT_DIR%\%INPUT_FILENAME% 1>NUL 2>NUL
IF %ERRORLEVEL% EQU 1 (
SET MESSAGE=Input files not present.
goto END
)
FOR /F "usebackq tokens=* eol= delims= " %%d IN (`date /t`) do SET RUNDATE=%%d
echo [%RUNDATE% %TIME%] Input files found. Start Processing...
FOR /F "usebackq" %%I IN (`dir /b %INPUT_DIR%\%INPUT_FILENAME%`) DO (
SET INPUT_FILE=!INPUT_DIR!\%%I
echo READING Input file: !INPUT_FILE!
SET N=
FOR /F "tokens=* eol= delims= " %%A IN (!INPUT_FILE!) Do (
set LINE=%%A
set LINE2=!LINE:~0,6!
if !LINE2! EQU !REC! (
SET /A N+=1
echo Creating temp file !TEMP_DIR!\!N!.tmp
)
echo !LINE! >> !TEMP_DIR!\!N!.tmp
)
FOR /F "usebackq" %%Y in (`dir /b !TEMP_DIR!\*.tmp`) DO (
SET TEMPFILE=!TEMP_DIR!\%%Y
SET N=
FOR /F %%A IN (!TEMPFILE!) DO (
SET /A N+=1
IF !N! EQU 3 SET S=%%A
IF !N! EQU 4 SET T=%%A
)
SET S=!S:~0,10!
SET T=!T:~0,10!
echo CREATING Output File: %OUTPUT_DIR%\V_!S!00!T!.TXT
MOVE !TEMPFILE! %OUTPUT_DIR%\V_!S!00!T!.TXT
)
)
REM %%%%%%%%%%%%%%%%%%%%%%%%% Archiving Section %%%%%%%%%%%%%%%%%%%%%%%%%
FOR /F "usebackq" %%t IN (`cscript "%~dp0timestamp.vbs" //Nologo`) do SET TIMESTAMP=%%t
FOR /F "usebackq" %%I IN (`dir /b %INPUT_DIR%\%INPUT_FILENAME%`) DO (
echo ARCHIVING Input file %%I to %ARCHIVE_DIR%
rem COPY !INPUT_DIR!\%%I !ARCHIVE_DIR!\%%I.!TIMESTAMP!
MOVE !INPUT_DIR!\%%I !ARCHIVE_DIR!\%%I.!TIMESTAMP!
)
REM %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FOR /F "usebackq tokens=* eol= delims= " %%d IN (`date /t`) do SET RUNDATE=%%d
SET MESSAGE=[%RUNDATE% %TIME%] Processing Done.
:END
echo %MESSAGE%
FOR /F "usebackq tokens=* eol= delims= " %%d IN (`date /t`) do SET RUNDATE=%%d
echo [%RUNDATE% %TIME%] Script finished.
As you can see, its quite sophisticated, and I have no idea how to make these changes myself. The BAT runs perfectly, but the number of zeroes if fixed, and not generated depending on the number of digits already present. Any help appreciate
I'm not about to read all of your code, but I use this for padding zeros.
The first line is whetever number you read from your file.
The second line pads more than enough zeros to the start of the variable.
The third line cuts off all but the last five characters from the variable.
Set Number=123
Set Number=00000%Number%
Set Number=%Number:~-5%
Related
#echo off
ren "(1) Rare Imports Exclusive.txt" "1RareImportsExclusive.txt"
set "replace="unid": 0,"
set "replaced="unid": 1,"
set "source=1RareImportsExclusive.txt"
set "target=1RareImportsExclusive1.txt"
setlocal enableDelayedExpansion
(
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" %source%') do (
set "line=%%b"
if defined line set "line=!line:%replace%=%replaced%!"
echo(!line!
)
) > %target%
ren "1RareImportsExclusive1.txt" "(1) Rare Imports Exclusive.txt"
del "1RareImportsExclusive.txt"
endlocal
I have update my Original Post
I have over 1000 .txt files, and in the content of each file has a UNID code
with random numbers
My goal is to have 1 bat file that can ignore all random numbers and
rename the unid based on the file number
Original files
(1) Rare Imports Exclusive.txt
------- "unid": 2548,"
Outcome files
(1) Rare Imports Exclusive.txt
------- "unid": 1,"
I can only get this to work if I change all unid to 0,
and if I make 1000 .bat files
So I make as many batch files and merge them
This works for now
#ECHO Off
setlocal ENABLEDELAYEDEXPANSION
set "replacemain="unid": "
SET "sourcedir=u:\sourcedir\t w o"
SET "destdir=u:\destdir"
FOR /f "delims=" %%q IN ('dir /b /a-d "%sourcedir%\(*)*.txt"') DO (
(
FOR /f "tokens=1 delims=()" %%j IN ("%%q") DO (
rem %%j now has sequence number
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" "%sourcedir%\%%q"') do (
set "line=%%b"
if defined line IF "%%b" neq "!line:unid=!" CALL :subs %%j
echo(!line!
)
)
)>"%destdir%\%%q"
)
GOTO :eof
:: substitute
:subs
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%replacemain%%%s=%replacemain%!"
IF "%original%" neq "%line%" goto subs
set "line=!line:%replacemain%=%replacemain%%1!"
GOTO :eof
As I read it, this problem has nothing to do with renaming files, but changing their contents.
You would need to change the settings of sourcedir and destdir to suit your circumstances. The listing uses a setting that suits my system.
I deliberately include spaces in names to ensure that they are processed correctly.
So, assuming that the filenames in the source directory follow the pattern (?) filename.txt and the required work is to replace the string "unid": ##, with "unid": ?, (where ## is a random number and ? is the number from the filename...
Grab the filenames to %%q and derive the filenumber to %%j.
Read and regurgitate. Detect whether the line contains unid etc. and further process these using :subs.
In :subs, replace the unid,etc. string followed by a digit by the string without the digit. If any change was made, repeat. Then substitute %%j passed as %1 to the :subs routine.
--- Revision for including subdirectories.
#ECHO Off
setlocal ENABLEDELAYEDEXPANSION
:: Significant part of string
set "replacemain="unid": "
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
FOR /f "delims=" %%q IN ('dir /b /s /a-d "%sourcedir%\(*)*.txt"') DO (
rem calculate new destination directory
SET "newdest=%%~dpq"
SET "newdest=!newdest:%sourcedir%=%destdir%!"
SET "newdest=!newdest:~0,-1!"
MD "!newdest!" 2>nul
(
FOR /f "tokens=1 delims=()" %%j IN ("%%~nxq") DO (
rem %%j now has sequence number
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" "%%q"') do (
set "line=%%b"
if defined line IF "%%b" neq "!line:unid=!" CALL :subs %%j
echo(!line!
)
)
)>"!newdest!\%%~nxq"
)
GOTO :eof
:: substitute
:subs
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%replacemain%%%s=%replacemain%!"
IF "%original%" neq "%line%" goto subs
set "line=!line:%replacemain%=%replacemain%%1!"
GOTO :eof
You would need to change the values assigned to sourcedir and destdir to suit your circumstances. The listing uses a setting that suits my system.
I deliberately include spaces in names to ensure that the spaces are processed correctly.
First, addition of /s in the dir command to cause scanning of subdirectories. This means that %%q will contain the absolute filename of each file that fits the mask (*)*.txt.
Since the destination directory may now change, newdest is calculated by replacing the value of sourcedir with the value of destdir and removing the final \ character since %%~dpq will deliver a \-terminated string.
The directory thus calculated is then created with a md instruction, and any objection from the system (as it's likely the directory already exists) is discarded with 2>nul (send error messages nowhere).
Since %%q originally contained the filename only, we need to specifically select the name and extension of %%q (%%~nxq) when calculating %%j.
Since %%q contains the absolute filename, we remove the %sourcedir% from the file-read loop using %%a.
Finally, the destination file needs to be constructed from the calculated newdest and the name+extension of the sourcefile.
--- Re-revision
#ECHO Off
setlocal ENABLEDELAYEDEXPANSION
:: Significant part of string
set "replacemain="unid": "
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
:: for tracking directory-changes
SET "lastdir="
SET /a serial=1
FOR /f "delims=" %%q IN ('dir /b /s /a-d "%sourcedir%\(*)*.txt"') DO (
rem use following line to restart serial number for each file
REM SET /a serial=1
if "!lastdir!" neq "%%~dpq" (
rem use following line to restart serial number for each directory
REM SET /a serial=1
rem calculate new destination directory
SET "newdest=%%~dpq"
SET "lastdir=%%~dpq"
SET "newdest=!newdest:%sourcedir%=%destdir%!"
SET "newdest=!newdest:~0,-1!"
MD "!newdest!" 2>NUL
)
(
rem %%j will acquire sequence number for filename pattern (*)*.txt
REM FOR /f "tokens=1 delims=()" %%j IN ("%%~nxq") DO SET "serial=%%j"
rem use following line to select a random serial number for each file
REM CALL :randsn
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" "%%q"') do (
set "line=%%b"
if defined line IF "%%b" neq "!line:unid=!" CALL :subs
echo(!line!
)
)>"!newdest!\%%~nxq"
)
GOTO :eof
:: substitute
:subs
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%replacemain%%%s=%replacemain%!"
IF "%original%" neq "%line%" goto subs
set "line=!line:%replacemain%=%replacemain%%serial%!"
SET /a serial+=1
GOTO :eof
:randsn
SET /a serial=%RANDOM%
:: Ignore selections 30000..32767 for even distribution
IF %serial% geq 30000 GOTO randsn
:: Use 10000 for 4-digit maximum, 1000 for 3, 100 for 2
SET /a serial=serial %% 10000
:: Use the following line if 0 is not allowed
IF %serial%==0 GOTO randsn
GOTO :eof
This provides a choice of how the number is calculated.
To activate any particular option, change the REM in the line following the comment to (nothing). It would probably be insane to try to activate more than one option at any one time. To deselect an option, put the REM keyword back in place.
The random option will generate a random 1-4-digit number. There is absolutely no guarantee whatever that the numbers inserted in this case will be unique.
To allow the routine to operate on any file in the tree, simply change the filemask (*)*.txt to some other filemask, noting that the derivation of sequence number for filenames that do not start (number) via %%j would then become nonsense, so the setting of serial from %%j should be de-activated with a rem statement (as posted)
I have some files in the form:
filename1 1 extra1.ext
filename1 2.ext
filename1 3 extra2.ext
...
filename2 1.ext
filename2 100 extra3.ext
...
filename20 1.ext
filename20 15 extra100.ext
(etc.)
...where filename1, filename2, etc., can contain spaces, symbol ' but not numbers. And extra1, extra2, etc, can contain anything. The number in the file name enclosed by spaces does not repeat per same filename1, filename2, etc.
What i want is to remove the extra things of the files that contain it. That is, to get from filename20 15 extra100.ext to filename20 15.ext
My first attempt is this:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "FILE=file name 11 con sosas extras 2.txt"
set "ext=txt"
set "folder=."
for /F "tokens=1,* delims=0123456789" %%A in ("!FILE!") do (set "EXTRA=%%B")
set "FIRST=!FILE:%EXTRA%=!"
set "filename=!FIRST!.!ext!"
echo !EXTRA!
echo !filename!
echo rename "!folder!\!FILE!" "!filename!"
that seems to work, but if i change it to receive parameters, it doesn't:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "FILE=%1"
set "ext=%2"
set "folder=%3"
for /F "tokens=1,* delims=0123456789" %%A in ("!FILE!") do (set "EXTRA=%%B")
set "FIRST=!FILE:%EXTRA%=!"
set "filename=!FIRST!.!ext!"
echo !EXTRA!
echo !filename!
echo rename "!folder!\!FILE!" "!filename!"
where %1 is the filename, %2 is the extension and %3 is the folder in which the files are. Probably, the extension can be extracted inside the batch, but i don't know how to do it.
On another hand, i plan to use this batch into another one. There, there will be a for loop in (*.txt) and i don't know how to differentiate between files that have extra things (and then call this batch) from files that doesn't (and then not call this batch).
Regards,
use your method to extract the "extra-portion". In a second step, remove that extra-portion:
#echo off
setlocal enabledelayedexpansion
set "FILE=file name 11 con sosas extras 2.txt"
for /f "tokens=1,* delims=1234567890" %%a in ("%file%") do set new=!file:%%b=!%%~xb
echo %new%
%%~xb gives you the extension.
Here is a batch script that seeks the first purely numeric string portion enclosed within SPACEs, or in case it appears at the end, preceded by a SPACE, that occurs after some other text not consisting of SPACEs only. The part in front of the found number followed by a SPACE followed by the number itself are used for building the new file name.
This approach handles all valid characters for file names properly, even ^, &, %, !, ( and ).
So here is the code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SOURCE=.\test"
for /F "eol=| delims=" %%F in ('
dir /B "%_SOURCE%\*.ext" ^| findstr /R /I ^
/C:"^..* [0123456789][0123456789]*\.ext$" ^
/C:"^..* [0123456789][0123456789]* .*\.ext$"
') do (
set "FILE=%%F"
call :SPLIT FIRST NUM REST "%%~nF"
if defined NUM (
setlocal EnableDelayedExpansion
ECHO rename "!_SOURCE!\!FILE!" "!FIRST! !NUM!%%~xF"
endlocal
)
)
endlocal
exit /B
:SPLIT rtn_first rtn_num rtn_rest val_string
setlocal DisableDelayedExpansion
set "RMD=" & set "NUM=" & set "STR=%~4"
:LOOP
for /F "tokens=1,2,* delims= " %%I in ("%STR%") do (
if not "%%J"=="" (
(for /F "delims=0123456789" %%L in ("%%J") do rem/) && (
if not "%%K"=="" (
set "STR=%%J %%K"
goto :LOOP
)
) || (
set "NUM=%%J"
if not "%%K"=="" (
set "RMD=%%K"
)
)
)
)
set "STR=%~4"
if not defined NUM goto :QUIT
set "STR=%STR% "
call set "STR=%%STR: %NUM% =|%%"
for /F "delims=|" %%L in ("%STR:^^=^%") do set "STR=%%L"
:QUIT
(
endlocal
set "%~1=%STR%"
set "%~2=%NUM%"
set "%~3=%RMD%"
)
exit /B
After having tested the script, remove the upper-case ECHO command to actually rename any files.
I have written a batch file which I want to overwrite key strings with strings from another .txt file.
currently it copies the new File.txt file perfectly but does not replace the strings with the strings from OldFile.txt file.
example of strings in File.txt file:
...
# Password
Pword=
# AccountName
Account=
# TownName
Town=
# Postcode
Postcode=
# LocationChangedDate
LocationChanged=
example of strings in OldFile.txt file I want to replace from:
...
# Password
Pword=ABC
# AccountName
Account=123
# TownName
Town=LDN
# Postcode
Postcode=WS77TP
# LocationChangedDate
LocationChanged=01/01/2015
Can someone please point me in the right direction or explain where I have made a mistake?
#echo off
setlocal disableDelayedExpansion
::Variables
set InputFile=F:\EXCHANGE\3\Machine\File.txt
set OutputFile=F:\EXCHANGE\3\File-New.txt
set CopyFile=F:\EXCHANGE\3\OldMachine\OldFile.txt
set _strFindPword=Pword=.*
for /F "delims=" %%A in ('findstr /x "Pword=.*" %CopyFile%') do set _strInsertPword=%%A
echo.%_strInsertPword%
set _strFindAccount=Account=.*
for /F "delims=" %%B in ('findstr /x "Account=.*" %CopyFile%') do set _strInsertAccount=%%B
echo.%_strInsertAccount%
set _strFindTown=Town=.*
for /F "delims=" %%C in ('findstr /x "Town=.*" %CopyFile%') do set _strInsertTown=%%C
echo.%_strInsertTown%
set _strFindLocationChanged=LocationChanged=.*
for /F "delims=" %%D in ('findstr /x "LocationChanged=.*" %CopyFile%') do set _strInsertLocationChanged=%%D
echo.%_strInsertLocationChanged%
set _strFindPostcode=Postcode=.*
for /F "delims=" %%E in ('findstr /x "Postcode=.*" %CopyFile%') do set _strInsertPostcode=%%E
echo.%_strInsertPostcode%
(
for /F "delims=" %%L in ('findstr /n "^" "%InputFile%"') do (
set "line=%%L"
setlocal EnableDelayedExpansion
set "line=!line:*:=!"
if "%%L" equ "_strFindPword" (echo.!_strInsertPword!) else (
if "%%L" equ "%_strFindAccount%" (echo.!_strInsertAccount!) else (
if "%%L" equ "%_strFindTown%" (echo.!_strInsertTown!) else (
if "%%L" equ "%_strFindLocationChanged%" (echo.!_strInsertLocationChanged!) else (
if "%%L" equ "%_strFindPostcode%" (echo.!_strInsertPostcode!) else (echo.!line!)
)
)
)
)
endlocal
)
) > "%OutputFile%"
del %InputFile%
ren %OutputFile% File.txt
pause
I think I finally got it...
What it does:
It goes through the OldFile.txt content, searching for markers, if found they are stored into environment variables to be used in the nest step (e.g. for _PWD marker (variable) which has a value of Pword=, it will create a _PWDCONTENTS variable with the content of Pword=ABC).
It goes through File.txt content, searching for the same markers, if one marker found, the corresponding CONTENTS variable is dumped in the OutFile.txt, else the original line. Because that happens in the inner for loop, I had to add some extra logic (the _WROTE var) to avoid writing the same lines more than once.
Notes:
It is supposed (well, besides doing what it's supposed to) to be "configurable" (the code is complicated, it's heading towards meta :) if you will), meaning that if there are changes between the markers the code shouldn't change (well there would be code changes, but not in the functional part only in variable definitions). Let me detail:
If you no longer need to replace the Town= string, then all you have to do is removing _TOWN from _ALL: set _ALL=_PWD _ACCT _POST _LOC.
The reverse: if you want to add some other tag (let's call it Name), you have to create a new environment variable: set _NAME=Name= and add it to _ALL: set _ALL=_PWD _ACCT _TOWN _POST _LOC _NAME.
As an indirect consequence, I didn't focus on performance, so it might run slow. Anyway I tried to keep the disk accesses (which are painfully slow) to a minimum (one example is when having 2 for loops the one that iterates on a file contents - assuming that each iteration takes a disk access; this might not be true, and Win has IO buffering - it's the outer one).
I "commented" out the last line in the file, to avoid overwriting the original file. If that behavior is needed, simply remove the rem at the beginning.
Here's the batch code:
#echo off
setlocal enabledelayedexpansion
set _INFILE="File.txt"
set _OUTFILE="NewFile.txt"
set _OLDFILE="OldFile.txt"
set _PWD=Pword=
set _ACCT=Account=
set _TOWN=Town=
set _POST=Postcode=
set _LOC=LocationChanged=
set _ALL=_PWD _ACCT _TOWN _POST _LOC
echo Parsing old file contents...
for /f "tokens=*" %%f in ('type !_OLDFILE!') do (
for %%g in (!_ALL!) do (
echo %%f | findstr /b /c:!%%g! 1>nul
if "!errorlevel!" equ "0" (
set %%gCONTENTS=%%f
)
)
)
copy nul %_OUTFILE%
echo Merging the old file contents into the new file...
set _WROTE=0
for /f "tokens=*" %%f in ('findstr /n "^^" !_INFILE!') do (
set _TMPVAR0=%%f
set _TMPVAR0=!_TMPVAR0:*:=!
for %%g in (!_ALL!) do (
echo !_TMPVAR0! | findstr /b /c:!%%g! 1>nul
if "!errorlevel!" equ "0" (
echo.!%%gCONTENTS!>>!_OUTFILE!
set _WROTE=1
)
)
if "!_WROTE!" equ "0" (
echo.!_TMPVAR0!>>!_OUTFILE!
) else (
set _WROTE=0
)
)
rem copy /-y %_OUTFILE% %_INFILE%
#EDIT0: Using #StevoStephenson suggestion (as part of the question snippet), I replaced the (2nd) outer for loop to ('findstr /n "^^" !_INFILE!') in order to include the empty lines, so the 3rd remark no longer applies (deleting). Also did some small changes to allow files that contain SPACE s in their paths.
Maybe it works like this
set CopyFile=oldfile.txt
set InputFile=newfile.txt
set str_search="Pword"
for /f "delims=" %%i in ('findstr %str_search% %copyfile%') do set str_replace=%%i
set str_replace="%str_replace%"
echo %str_search%
echo %str_replace%
pause
CALL :far %InputFile% %str_search% %str_replace%
EXIT /B 0
:far
setlocal enableextensions disabledelayedexpansion
set "search=%2"
set "replace=%3"
::remove quotes
set search=%search:"=%
set replace=%replace:"=%
echo %search%
echo %replace%
set "textFile=%1"
for /f "delims=" %%i in ('type "%textFile%" ^& break ^> "%textFile%" ') do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%replace%!"
>>"%textFile%" echo(!line!
endlocal
)
EXIT /B 0
At for /f "delims=" %%i in ('findstr %str_search% %copyfile%') do set str_replace=%%i you write the line with the variable that has the needed info to str_replace.
After that you the program calls an embeded find-and-replace-function (:far) whitch i shemelessly stole from Batch script to find and replace a string in text file without creating an extra output file for storing the modified file
This function finds the string "Pword" and replaces it by the line find in the old file.
Attention:
This doesn't solve your problem completely since your new file has to be s.th like this.
#Password
Pword
so if you loose the = it works otherwise it doesn't. I hope this helps you with your problem.
It's not perfect but this may be okay for you:
#Echo Off
Setlocal EnableExtensions DisableDelayedExpansion
(Set InputFile=F:\EXCHANGE\3\Machine\File.txt)
(Set OutputFile=F:\EXCHANGE\3\File-New.txt)
(Set CopyFile=F:\EXCHANGE\3\OldMachine\OldFile.txt)
For /F "Delims=" %%I In (
'FindStr/B "Pword= Account= Town= LocationChanged= Postcode=" "%CopyFile%"'
) Do Set %%I
(For /F "Tokens=1-2* Delims=]=" %%I In ('Find /V /N ""^<"%InputFile%"') Do (
Echo(%%J|FindStr/B # || (If Defined %%J (Call Echo=%%J=%%%%J%%) Else (
If "%%J" NEq "" (Echo=%%J=%%K) Else (Echo=)))))>%OutputFile%
Timeout -1
EndLocal
Exit/B
I've left the delete and rename for you to add at the end.
This solution should be much faster than the other solutions.
It will also preserve empty lines and lines containing ! and ^.
It only needs one findstr call for collecting the old values for all words.
A second findstr determines all lines (by line number) in the infile which needs an update.
#echo off
setlocal EnableDelayedExpansion
set "_INFILE=File.txt"
set "_OUTFILE=NewFile.txt"
set "_OLDFILE="OldFile.txt"
set "_WORDS=Pword= Account= Town= Postcode= LocationChanged="
REM *** get all values for the key words
for /F "tokens=1,* delims==" %%L in ('findstr "!_WORDS!" "!_OLDFILE!"') do (
for /F %%S in ("%%L") do (
set "word[%%S]=%%M"
)
)
REM *** Find all lines which needs an update
set wordIdx=0
for /F "tokens=1,2,* delims=:= " %%1 in ('findstr /n "!_WORDS!" "!_INFILE!"') do (
set "lines[!wordIdx!].line=%%1"
set "lines[!wordIdx!].word=%%2"
set "replace=!word[%%2]!"
set "lines[!wordIdx!].replace=!replace!"
set /a wordIdx+=1
)
REM *** copy the infile to the outfile
REM *** Replace only the lines which are marked by line numbers
echo Parsing old file contents...
set nextWordIdx=0
set /a searchLine=lines[!nextWordIdx!].line
set lineNo=0
setlocal DisableDelayedExpansion
(
for /f "tokens=*" %%L in ('findstr /n "^" "%_INFILE%"') do (
set "line=%%L"
set /a lineNo+=1
setlocal EnableDelayedExpansion
set "line=!line:*:=!"
if !lineNo! equ !searchLine! (
(echo(!line!!lines[0].replace!)
set /a nextWordIdx+=1
for /F %%R in ("!nextWordIdx!") do (
endlocal
set /a nextWordIdx=%%R
set /a searchLine=lines[%%R].line
)
) ELSE (
(echo(!line!)
endlocal
)
)
) > "!_OUTFILE!"
Example below - 5 files will be located in the same folder.
Sales-fid1000-f100.dat
Revenue-fid1000-f100.dat
Sales-fid2000-f200.dat
Revenue-fid2000-f200.dat
Income-fid2000-f200.dat
I need to read the filename and get the number after "fid", in this case 1000 and 2000 and count the number of files associated with each "fid".
So for fid1000, there are 2 files and for fid2000, there are 3 files.
I need to write the output into a .txt file as below with first field being the fid number and second field being the count.
1000|2
2000|3
How can I generate output text file with fid and count using a Windows batch file?
#echo off
setlocal EnableDelayedExpansion
rem Process all file names
for /F "tokens=2 delims=-" %%a in ('dir /B /A-D *.dat') do (
rem Get FID from second dash-delimited token; format: "xxx-fid####-xxx.dat"
set "fid=%%a"
rem Accumulate it to the corresponding element of "count" array
set /A "count[!fid:~3!]+=1"
)
rem Create the output
(for /F "tokens=2,3 delims=[]=" %%a in ('set count[') do echo %%a^|%%b) > output.txt
For further details on array management in Batch files, see: Arrays, linked lists and other data structures in cmd.exe (batch) script
#ECHO OFF
SETLOCAL
:: remove variables starting $
FOR /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a="
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "outfile=%destdir%\outfile.txt"
FOR /f "delims=" %%a IN (
'dir /b /a-d "%sourcedir%\*-fid*" '
) DO (
SET "filename=%%a"
CALL :process
)
(
FOR /F "tokens=1,2delims=$=" %%a In ('set $ 2^>Nul') DO ECHO(%%a^|%%b
)>"%outfile%"
GOTO :EOF
:process
SET "filename=%filename:*-fid=%"
FOR /f "delims=-" %%q IN ("%filename%") DO SET /a $%%q+=1
GOTO :eof
You would need to change the settings of sourcedir and destdir to suit your circumstances.
Produces the file defined as %outfile%
After clearing all the $ variables (for safety's sake), perform a directory listing without directorynames and in basic form of files in the source directory matching *-fid*.
For each name found, assign the name to filename and execute the :process routine, which first removes the characters up to and including -fid from filename then uses the delims=- option to assign the part originally between -fid and the following - to %%q.
setthe variable $%%q up by 1 (if $?? is undefined, assign 1)
Finally, when all the names have been processed, list the variables named $... using set which produces a report of the style
$1000=2
$2000=3
Using $ and = as delimiters puts token 1 (eg 2000) into %%a and token 2 (eg 3) into %%b. Write these to the output using echo, remembering to escape the pipe (|) with a caret (^) to suppress the interpretation as a redirector.
The parentheses around the for...$... ensures the output is directed to the destination file specified.
Extract the numbers into a temporary file, then count the occurrences of each number in that file.
#echo off
setlocal EnableDelayedExpansion
>temp.txt type nul
set "unique_num="
for /f "tokens=2 delims=-" %%a in ('dir /b *.dat') do (
set "fid=%%a"
set "num=!fid:~3!"
>>temp.txt echo !num!
echo " !unique_num! " | find " !num! " >nul
if !errorlevel! neq 0 set "unique_num=!unique_num! !num!"
)
for %%n in (%unique_num%) do (
for /f "delims=: tokens=2" %%c in ('find /c "%%n" temp.txt') do (
set "count=%%c"
echo %%n^|!count: =!
)
)
del /f /q temp.txt
Pipe the result into sort if you need the output sorted.
I have a directory with following files:
PPP1234MM.xml
PPP4532MM.xml
PPP9843MM.xml
I need to extract the numeric parts of the filenames using batch command. Please help!
for /f "tokens=*" %%f in ('dir /l /a-d /b *.xml') do (
for /f "tokens=1 delims=abcdefghijklmnopqrstuvwxyz" %%n in ("%%~nf") do (
echo File: %%~nxf = Number %%n
)
)
Use the non numeric characters as delimiters in a for command to remove them of the name. The list of files is retrieved in lowercase to limit the number of delimiters in list.
If the pattern is the same of your question (3 characters, 4-digit, 2 characters), use the code below, if you have other standards to help inform you better.
#echo off
#title Get Part of filename batch
#color 0a
setlocal EnableDelayedExpansion
for %%A in ( "*.xml" ) do (
REM Set Filename
set "FileFull=%%~nxA"
REM Set Number, offset equal 3 (skip 3 first characteres), length equal 4 (four characteres)
set "FileNumber=!FileFull:~3,4!"
echo !FileNumber!
)
pause
exit
#ECHO OFF
SETLOCAL
FOR /f "delims=" %%a IN (
'dir /b /a-d "ppp*.xml" '
) DO (
SET "number="
SET "name=%%a"
CALL :process "%%a"
)
GOTO :EOF
:notnum
IF DEFINED number GOTO show
:num
SET "name=%name:~1%"
:process
IF NOT DEFINED name GOTO show
if "%name:~0,1%" lss "0" GOTO notnum
if "%name:~0,1%" gtr "9" GOTO notnum
SET "number=%number%%name:~0,1%"
GOTO num
:show
ECHO file %1 --^> %number%
GOTO :eof
This should extract and show the numeric part. You may wish to change the filematch mask. I simply used ppp*.xml for my testing