Is it possible to use FINDSTR with a variable instead of a file?
I've tried researching this but my knowledge on batch isn't good enough yet.
I've made most of my batch file work flawlessly for what I need, but I'm having trouble extracting part of a string variable into a new variable.
The original variable for example would be S02E12 - Charge!. I would like to extract 02 to ep_seas, 12 to ep_num, and Charge! to ep_name. I have it working right now if that's the exact pattern of names, but I've come across some files that are in this pattern: S02E124 - Charge #2!
Is there a way I can dynamically get the values I need regardless of their length?
My idea was to use FINDSTR to search between the S and the E, then between E and space (or -), then between - and the end. I'm not sure how I would proceed with this though.
Does anyone have a solution I can look into or can someone provide an example?
setlocal DisableDelayedExpansion
set mkvmerge="C:/Program Files/MKVToolNix/mkvmerge.exe"
set "output_folder=%cd%\Muxing"
for /r %%a in (*.mkv) do (
set fi=%%a
set ep=%%~na
call :merge
)
goto :eof
:merge
set ep_name=%ep:~9%
set ep_num=%ep:~4,2%
set ep_seas=%ep:~2,1%
call %mkvmerge% -o "%output_folder%\%ep%.mkv" --track-name "0:%ep_name%" --language 0:und --default-track 0:yes --track-name "1:[JAP]" --language 1:jpn --default-track 1:yes --track-name "2:[ENG]" --language 2:eng --default-track 2:yes --forced-track 2:yes "%fi%" --track-order 0:0,0:1,0:2 --title "Fate Zero - Episode %ep_num%"
goto :eof
You could use this code for your task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "output_folder=%CD%\Muxing"
for /R %%I in (*.mkv) do (
set "fi=%%I"
set "ep=%%~nI"
call :merge
)
goto :EOF
:merge
for /F "tokens=1,2* delims=ES- " %%A in ("%ep%") do (
set "ep_seas=%%A"
set "ep_num=%%B"
set "ep_name=%%C"
)
"%ProgramFiles%\MKVToolNix\mkvmerge.exe" -o "%output_folder%\%ep%.mkv" --track-name "0:%ep_name%" --language 0:und --default-track 0:yes --track-name "1:[JAP]" --language 1:jpn --default-track 1:yes --track-name "2:[ENG]" --language 2:eng --default-track 2:yes --forced-track 2:yes "%fi%" --track-order 0:0,0:1,0:2 --title "Fate Zero - Episode %ep_num%"
goto :EOF
The command FOR /F as used here parses the string in double quotes which is the file name.
The option "tokens=1,2* delims=ES- " results in splitting up the file name strings S02E12 - Charge! and S02E124 - Charge #2! into 3 substrings using the 4 specified characters as delimiters.
Token 1 is 02 for both file names assigned to specified loop variable A.
Token 2 is 12 and 124 for the two file names assigned to next loop variable after A according to ASCII table which is B.
Token 3 is everything after the delimiters after token 2 which is Charge! and Charge #2! for the two files assigned to next but one loop variable C.
You know now why loop variables are case-sensitive while environment variables are not case-sensitive. The specified loop variable defines which characters the next loop variables have on using for /F with more than one token/substring.
* appended to a token number X means rest of the string/line after the delimiters after substring X should be assigned to next loop variable without any further splitting on delimiters. So the string after S02E12 - and S02E124 - can contain also delimiter characters and is nevertheless assigned completely to loop variable C.
Please note that a string starting with E or S after hyphen and space is interpreted also as delimiter and therefore missing in string assigned to loop variable C. The FOR loop in subroutine merge could be replaced by following code to get a working solution for a file name like S03E48 - Extended Version.mkv.
for /F "tokens=1* delims=- " %%A in ("%ep%") do (
set "ep_name=%%B"
for /F "tokens=1,2 delims=ES" %%C in ("%%A") do (
set "ep_seas=%%C"
set "ep_num=%%D"
)
)
The outer loop assigns S03E48 to loop variable A and Extended Version to loop variable B. The inner loop splits up S03E48 once again into 03 assigned to loop variable C and 48 assigned to loop variable D.
By the way: The directory separator on Windows is \ and not / as on Unix/Linux/Mac although Windows kernel functions support also file/directory paths with / with automatic correction to \.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
echo /?
endlocal /?
for /?
goto /?
set /?
setlocal /?
One last note:
It is possible to use FINDSTR on an environment variable for example with:
echo %ep% | findstr /R "^S[0123456789][0123456789]"
But FINDSTR never outputs just the matching string. It always outputs the entire line containing the found string. So FINDSTR is of no help here for splitting the file name up into separate parts.
I have a .txt file with some data in it, where "BARREL-5, BODY-3" etc are what is being measured, the decimal after the "V" is the measured value, and the date (sans the exact time) is being used to identify which sample the measurement belongs to, as such
4491 316 SS,BARREL-5,V,1.393,5/7/2015 7:47:05 AM,0,,,,13,...
4491 316 SS,BARREL-5,V,1.3865,2/17/2016 11:26:12 AM,0,,,,13,...
4491 316 SS,BODY-3,V,1.256,5/6/2015 6:45:42 PM,0,,,,13,...
4491 316 SS,BODY-3,V,1.2565,5/7/2015 7:46:16 AM,0,,,,13,...
4491 316 SS,BODY-3,V,1.246,2/17/2016 11:24:18 AM,0,,,,13,...
This data is exported from a (really obsolete) program in .txt format only every time we take sample measurements for a batch of parts. The data needs to be viewable in excel to quickly determine if the batch of parts is in tolerance or not. The problem with changing an extension and going with it is that a full line of data is as follows:
4491 316 SS,BARREL-5,V,1.393,5/7/2015 7:47:05 AM,0,,,,13,Blow Pattern=1-1-1,Die Set=FN3,Forge=Erie,Heat #=E150058,Job #=I2928,Lube Type=Hydraforge,Operator=Paul & ,Revision=C,Run Temperature=2250,Shift=2nd,Shim bottom Die=X,Shim Top Die=X,Shim Trimmer=X,C
This comes out really messy in excel, and the number of columns can vary +1 sometimes (it adds a column following the 0 in 0,,,, if that 0 is instead a 1).
My desired output, in txt format, would look something like this:
Project Number: 4491,,,, Material: 316 SS
,5/7/2015,2/17/2016,5/6/2015
BARREL-5,1.393,1.3865,NA
BODY-3,1.256,1.2565,1.246
Right now I loop through all the lines, extract all the dates, remove any duplicates (down to a list of each unique date), and then turn those into a string in the csv file as such ,date1,date2,date3,etc.
I then loop through the data file again and put the variable name down on a new line, checking first to see if it is repeated and if so, not echoing that variable name. I am using the following for loop to do this (filePath is a file path and project number combined, with the file extension or name-addition to be added on as needed):
for /f "tokens=1 delims=," %%a IN (%filePath%.txt) DO (
set varname=%%a%
find "!varname!" %filePath%Excel.csv
if !errorlevel!==1 (echo !varname! >> %filePath%Excel.csv)
)
My current output essentially looks something like this:
Project Number: 4491,,,, Material: 316 SS
,5/7/2015,2/17/2016,5/6/2015
BARREL-5,
BODY-3,
As you can see, I need to put the actual measured values in their proper locations. Is there any easy way to do this in batch? The code must be easily run by anyone, on any computer (Win 7 and XP). The data files are unlikely to change anytime soon, so the program doesn't need to be very robust. I am also limited by the fact that I tried using Powershell but discovered that I am not allowed to run any scripts on any of the computers...
The approach I hesitate to dig into would be something along the lines of creating a list of the line numbers for each line which switches to a new measurement name, then running another loop through the file and printing all the values on the same line, breaking them up based on the line count. The lines of variables would then be concatenated to the proper lines in the csv file.
Thanks for any help. I have edited this to include more relevant examples and details.
Your description is confusing and you did not shown what is the desired output, so there is no way to try to write a solution to your problem... However, your partial requirements can be obtained via a Batch file in a very simple way:
#echo off
setlocal EnableDelayedExpansion
set "dates="
for /F "tokens=1-3 delims=," %%a in (test.txt) do (
rem Get a list of unique dates:
set "dates=!dates:%%c,=!%%c,"
rem Take the values of the variables
set "var[%%a]=!var[%%a]!,%%b"
)
rem Show the results
echo Dates: %dates:~1,-1%
echo/
echo Variables:
for /F "tokens=2* delims=[]=" %%a in ('set var[') do echo %%a%%b
Using this data as input file:
varname1,valueA,date1
varname1,valueB,date2
varname1,valueC,date3
varname2,valueD,date1
varname2,valueE,date2
varname2,valueF,date3
... this is the output:
Dates: date1,date2,date3
Variables:
varname1,valueA,valueB,valueC
varname2,valueD,valueE,valueF
EDIT: Code modified to fulfill the new specifications
#echo off
setlocal EnableDelayedExpansion
set "max=0"
set "dates=,"
for /F "tokens=1-4,6,7 delims=, " %%a in (test.txt) do (
rem Get header data
set "project=%%a" & set "material=%%b %%c"
rem Get a list of unique dates
if "!dates:%%f=!" equ "!dates!" set "dates=!dates!%%f,"
rem Take the values of the variables
set "var[%%d]=!var[%%d]!,%%e"
rem Get data for variable equalization
set "data=%%d"
for /F %%D in ("!data:-=_!") do (
set /A "len[%%D]+=1"
if !len[%%D]! gtr !max! set "max=!len[%%D]!"
)
)
rem Equalize variables
set /A max-=1
for /F "tokens=2,3 delims=[]=" %%i in ('set len[') do (
set "data=%%i"
for /F %%D in ("!data:_=-!") do for /L %%I in (%%j,1,%max%) do (
set "var[%%D]=!var[%%D]!,NA"
)
)
rem Show the results
(
echo Project Number: %project%,,,, Material: %material%
echo %dates:~0,-1%
for /F "tokens=2* delims=[]=" %%a in ('set var[') do echo %%a%%b
) > output.txt
The output generated by this program is exactly the same specified in the question...
An easy way by 2 command lines to solve your question, see screenshot at bottom.
:: Extract all dates and get unqiue
msr -p your-source.txt -t "^.*?,(\d+/\d+/\d+)\s+(\d+:\d+:\d+).*" -o "$1" -PAC | nin nul -uPAC | msr -S -t "(\S+)\s+" -o ",$1" -PAC >> result.csv
:: Extract column2 like "BARREL-5" -> Auto classify -> Extract values like "1.393" -> Add "NA" if lack columns
for /f "tokens=*" %%a in ('nin source.txt nul "^[^,]+,([^,]+)" -u -PAC') do #msr -p source.txt -t ".*?,%%a,V,(\d+\.\d+),.*" -o "$1" -PAC | msr -S -t "\s+(\S+)" -o ",$1" -PAC | msr -t "^\d+\.?\d*,\d+\.?\d*$" -o "$0,NA" -aPAC| msr -t ".+" -o "%%a,$0" -PAC >> result.csv
But I don't know how you first line come out: Project Number: 4491,,,, Material: 316 SS
The above uses 2 common single exe tool (no dependencies): msr.exe (Match/Search/Replace) + nin.exe (Not-In-latter: get difference/intersection) in my open project https://github.com/qualiu/msr tools directory.
Use msr-Win32.exe and nin-Win32.exe if you're on a 32-bit Windows.
I'm trying to compare a bunch of files with names like
"BD12-CD9.txt"
to folders named
"BD12-CD9 - somefoldername"
I'm removing the .txt extension to get the ID code "BD12-CD9" and want to check if the folder name contains the code.
I can't figure out how to do this without an if statement that compares strings exactly. (might be an easy solution here like jQuery's indexOf())
So I need to strip the ID code from the file name and do a direct comparison.
The problem is the ids and names are not always exactly the same length e.g. "BD12-CD10.txt" so I can't just do "set folderName2=!folderName:~0,8!"
I found a strlength function and put it in another batch file called strlen.bat and it works great, echoing the length of my stripped ID codes. How do I use the echoed value though?
move.bat
#echo off
#setlocal enabledelayedexpansion
set "errfolderpath=C:\Testing\Moving txt files automatically\"
echo.
for %%x in (*.*) do (
set fileName=%%x
set fileName2=!fileName!
set fileName2=!fileName2:~0,-4!
call strlen !fileName2!
FOR /D %%K in ("%errfolderpath%*") DO (
SET folderName=%%~nK
set folderName2=!folderName!
set folderName2=!folderName:~0,11!
echo folder: !folderName2!, file: !fileName2!
if !folderName2! == !fileName2! echo MOVE '!fileName!' to '!folderName!'
)
echo %_len%
echo.
)
PAUSE
strlen.bat
#echo off
:: strlen.bat
:: http://acm.zhihua-lai.com
if [%1] EQU [] goto end
:loop
if [%1] EQU [] goto end
set _len=0
set _str=%1
set _subs=%_str%
:getlen
if not defined _subs goto result
:: remove first letter until empty
set _subs=%_subs:~1%
set /a _len+=1
goto getlen
:result
echo %_len%
shift
goto loop
:end
For the batch file variable usage, if you look to the code, a variable called _len is defined. This variable is then echoed to console, but is not removed (no reasignation, no endlocal, ...) , so just use it.
Anyway, it is easier than it seems.
#echo off
setlocal enableextensions disabledelayedexpansion
set "errfolderpath=C:\Testing\Moving txt files automatically"
for %%a in (*.txt) do (
set "notMoved=1"
for %%b in ("%errorfolderpath%\%%~na*") do if defined notMoved (
set "notMoved="
move "%%~fa" "%%~fb"
)
)
For each file, search a folder with the same prefix (the name of the file referenced in %%a, without extension, is %%~na). If found, move the file (the full path to the file is %%~fa) to the target folder and use a switch variable to "mark" the file as moved to avoid problems in the case of two folders with the same prefix (that will be retrieved in the inner for %%b) .
Example of 2 rows in text file (abc.txt):
PMIP_TSD_2012120323.csv:03/12/2012,22:51:53,CAU TACS,TS,PPT4I_TS22, AJAY,595959,P,Legal Exit,(6 0) AJAY,G1234567M,SERVICES P L,8401352W,
PMIP_TSD_2012111300.csv:12/11/2012,23:20:13,CAU TACS,TS,PPT4O_TS32,ARUMUGAM,620466,P,Legal Exit,(5 0) ARUMUGAM,G686W,SUPERSONIC SERVICES P L,1982W,
I would like every row to start with the date instead of the csv file name. Meaning removing the PMIP......csv: for every row. How can i do this using batch file? I have hundreds of rows, i do not wish to do it manually. My file name is abc.txt and it is located in D:\Int\ KGX
This Batch file do that:
#echo off
cd /D "D:\Int\KGX"
(for /F "tokens=1* delims=:" %%a in (abc.txt) do (
echo %%b
)) > abc-NEW.txt
perl -npi -e 's/[^:]+://' /tmp/abc.txt yields:
03/12/2012,22:51:53,CAU TACS,TS,PPT4I_TS22, AJAY,595959,P,Legal Exit,(6 0) AJAY,G1234567M,SERVICES P L,8401352W,
12/11/2012,23:20:13,CAU TACS,TS,PPT4O_TS32,ARUMUGAM,620466,P,Legal Exit,(5 0) ARUMUGAM,G686W,SUPERSONIC SERVICES P L,1982W,
from your data. Hope that helps...
I can give you my thoughts about the problem
We can use C++ or Java to solve this problem
Open the file
In a loop we get the row in a String variable
use SubString (or some kind of similar functions or utilities) to specify the first index number (in our case 23)
Store the sub string in a new file
finish the loop
The new file is what you want, and hope that helps
This should do it
setlocal enabledelayedexpansion
for /f "tokens=1,* delims=:" %%a in (abc.txt) do (
echo !date!:%%b >>new.txt
)
del abc.txt /f /q
ren new.txt abc.txt