Find in file then move the file - windows

I have an unknown number of text files in a directory which are named as such, ABC1200f1234.EAU, but they are all slightly different. The internal structure of each text file is the same, but the contents are different. Within each file there is a string * SERIAL NUMBER:XXXXX *. For each file the 6 characters following the SERIAL NUMBER: is different. I am trying to search each file to obtain the 6 digits following SERIAL NUMBER: then move that file to a directory named after the 6 digits, e.g. if the 6 digits are A12345 then I want to create a directory named A12345 and move the file there, then move on to the next file until all files have been moved.
The following code gets the 6 digits into %%a but I'm stuck on how to then move the file, before moving onto the next one. I'm sure I'm just missing one small piece of the puzzle.
#ECHO OFF
CLS
cd c\Temp
setlocal enableextensions disabledelayedexpansions
set sourcedir=c:temp
set targetdir=c:\temp\parsed
for /f "tokens=4 delims=*:" %%a in (
'findstr /r "SERIAL NUMBER:" %sourcedir%\*'
) do (
if exists %targetdir%\%%a (
echo Directory already exists
) else mkdir %targerdir%\%%a
)
move %sourcedir%\%%a %targetdir%\%%a
)
I'm sure the last line is the problem because %%a now holds the 6 digit number, not the filename.
Please don't suggest Powershell as that is not an option. I also realise I can use robocopy and remove the check to see if the target directory exists.
Any help you can give would be most appreciated.

I'm assuming for this code that the serial number is directly after the colon with no white space or other characters whcih need to be removed before or after it.
#(setlocal EnableDelayedExpansion
ECHO OFF
CLS
set "sourcedir=c:\temp"
set "targetdir=c:\temp\parsed"
SET "FileGlob=*.EAU"
)
CALL :Main
( Endlocal
EXIT /B
)
:Main
FOR %%_ IN (
"%sourcedir%\%FileGlob%"
) DO (
Echo=processing "%%~_"
FOR /F "Tokens=2 delims=:" %%F IN ('
TYPE "%%~_" ^| FIND /I "SERIAL NUMBER:"
') DO (
ECHO=Found. Serial number "%%F" trimmingbany spaces
FOR /F "Tokens=*" %%f IN ("%%~F") DO (
ECHO=Trimmed serial number "%%~f" stored
SET "_TmpFolder=%%F"
)
)
MD "%TargetDir%\!_TmpFolder!\"
MOVE "%%~_" "%TargetDir%\!_TmpFolder!\%%~nx_"
)
GOTO :EOF

There is not any need to test if the directory you're trying to create exists. Simply do mkdir and pipe the output to nul
NOTE! This example assumes that the Serial Number is on it's own line in the file, seeing as you have not shown an actual example of your text file.
#echo off
set "source=c:\temp"
set "target=c:\temp\parsed"
for %%a in ("%source%\*.EAU") do for /f "tokens=2* delims=:" %%i in ('type "%%~a" ^|findstr /i "serial number"') do (
mkdir "%target%\%%i">nul 2>&1
move "%%~a" "%target%\%%i"
)
As far as overwriting existing files are concerned, that is something you need to decide as I do not know your exact scenario, so did not include additional parameters to the move command.

Related

Batch script to add part of parent folder name to pdfs inside

I have a windows directory which contains folders with names like:
Lot 1
Lot 2
Lot 5
Lot A
Block A
Block C
Each of these folders contains PDF survey drawings. The names of the files are inconsequential. My goal is to prefix each PDF in ONLY LOT FOLDERS with an edited version of the name of its parent folder. Instead of adding the prefix Lot 1_ to the filenames of files in folder Lot 1 I would like to add L1_ to the filename.
Currently, I have a batch file which will add any prefix entered into a prompt to all PDFs in current folder. This means I have to go into each folder & run the batch script. This is tedious as I have thousands to deal with.
This is what the code looks like:
Set /p prefix="Enter Prefix to add to file names: "
FOR /f "delims=" %%F IN ('DIR /a-d /b *.PDF') DO (RENAME "%%F" %prefix%_"%%F")
I have been messing around trying to create a batch file to iterate through all folders with Lot and a space in their names and so far all I can do is use a for loop to get all the Lotwhatevernumber names and output them to a text file.
This is what that code looks like:
for /f "delims=" %%F in ('dir /A:D /b Lot*') do echo %%F >> folders.txt
and then I get text file with:
Lot 1
Lot 2
Lot 5
Lot A
I can also output just the number portion of the Folder name. That code:
for /f "tokens=2" %%F in ('dir /A:D /b Lot*') do echo %%F >> folders2.txt
and then I get text file with:
1
2
5
A
I felt like I was real close with that last one, but what I tried to do was instead of echoing to folders2.txt I wanted to enter another for loop where I would rename each file in Lot %%F and add a prefix of L%%F and the rest of the filename.
Anyone has any ideas?
Someone from another forum gave me this which works but the first file in each Lot folder gets named twice...I can't figure out why.
Someone on another forum provided the following which works but the first file in each Lot folder gets labelled L_ twice and I don't know why....
#echo off & setlocal
for /f "tokens=*" %%a in ('dir /b /ad lot*') do (
for %%b in ("%%a"\*.pdf) do call :xx "%%~dpb" "%%~nxb"
)
goto :eof
:xx
set z=%~1
set z=%z:~0,-1%
for %%c in ("%z%") do set k=%%~nc
set k=%k:lot =L%
echo ren %1%2 %k%_%2
ren %1%2 %k%_%2
What about this:
#echo off
rem // Switch to the target directory:
pushd "D:\Target" && (
rem /* Loop through all directories whose names begin with `Lot` + SPACE;
rem the `findstr` portion further filters the directory names so that
rem they must begin with `Lot` + SPACE + a character other than SPACE;
rem everything starting at a potential following SPACE is ignored: */
for /F "tokens=1-2" %%C in ('
2^> nul dir /B /A:D "Lot *" ^| findstr /I "^Lot [^ ]"
') do (
rem /* Loop through all `*.pdf` files in the currently iterated directory;
rem the `findstr` portion further filters the file names so that they must
rem not equal `L` + the second token from the outer loop + something containing
rem a `_` + `.pdf`, because such files are considered as already renamed: */
for /F "delims=" %%F in ('
2^> nul dir /B /A:-D "%%~C %%~D\*.pdf" ^| findstr /I /V "^L%%~D_.*\.pdf$"
') do (
rem // Check whether target file name already exists:
if exist "%%~C %%~D\L%%~D_%%F" (
rem // Collision, hence skip file and return error message:
>&2 echo Collision: cannot rename "%%~C %%~D\%%F" to "L%%~D_%%F"!
) else (
rem // No collision, so actually rename the currently iterated file:
ECHO ren "%%~C %%~D\%%F" "L%%~D_%%F"
)
)
)
rem // Return to original working directory:
popd
)
After having tested for the correct output, remove the upper-case ECHO from the ren command!

Batch file to make folders and move files according to filenames

I'm brand new to batch scripting so I appreciate any help. I've seen similar problems here but can't get my move function to work.
I have files with the following format:
19013_01-PG-18-1000_NC_IL2RG_Ex2_F_D01.ab1
19013_01-PG-18-1000_NC_IL2RG_Ex2_R_H01.ab1
I want to make folders with the following format:
01-PG-18-1000_NC_IL2RG_Ex2
And then move all the files that have *01-PG-18-1000_NC* into that folder name.
Here's what I have so far. It's making the folders the way I want, but I can't get the files to move at all. Tried multiple iterations of the move function, but I'm not totally understanding the tokens and how it relates to the files for moving.
#ECHO OFF
SETLOCAL
SET "sourcedir="whatever my directory name is"
PUSHD %sourcedir%
FOR /f "tokens=1,2,3,4,5 delims=_" %%a IN (
'dir /b /a-d "*_*-*-*-*_*_*_*.*"'
) DO (
MD %%b_%%c_%%d_%%e 2>nul
MOVE "%%b_%%c_%%d_%%e" "%%b_%%c_%%d_%%e"
)
POPD
GOTO :EOF
Real quickie - and untested
#ECHO OFF
SETLOCAL
SET "sourcedir="whatever my directory name is"
PUSHD %sourcedir%
FOR /f "tokens=1,2,3,4,5,* delims=_" %%a IN (
'dir /b /a-d "*_*-*-*-*_*_*_*.*"'
) DO (
echo ++%%a++%%b++%%c++%%d++%%e++%%f++
MD %%b_%%c_%%d_%%e 2>nul
MOVE "%%a_%%b_%%c_%%d_%%e_%%f" "%%b_%%c_%%d_%%e"
)
POPD
GOTO :EOF
You were very close - the echo line should show you how the filename is parsed into %%a..%%f. The parts separated by ++ which is simply a very obvious separator and shows whether there are spaces in any element.
Adding * to the token-list means "everything after the highest-mentioned token number". Then reconstruct the filename from the parts - string together starting at %%a, re-inserting all the underscores.
This should work also:
#ECHO OFF
SETLOCAL
SET "sourcedir="whatever my directory name is"
PUSHD %sourcedir%
FOR /f %%q IN (
'dir /b /a-d "*_*-*-*-*_*_*_*.*"'
) do (
FOR /f "tokens=1,2,3,4,5,* delims=_" %%a IN ("%%q") do
echo ++%%a++%%b++%%c++%%d++%%e++%%f++FROM++%%q++
MD %%b_%%c_%%d_%%e 2>nul
MOVE "%%q" "%%b_%%c_%%d_%%e"
)
)
POPD
GOTO :EOF
In this version, %%q acquires each filename in turn, then "%%q" can be parsed by for /f and the original filename remains unmolested in %%q ready for use in the move statement.
[actually, quite minor] Revision:
REM <!-- language: lang-dos -->
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir\t w o"
PUSHD "%sourcedir%"
FOR /f "tokens=1,2,3,4,5,* delims=_" %%a IN (
'dir /b /a-d "*_*-*-*-*_*_*_*.*"'
) DO IF EXIST "%%a_%%b_%%c_%%d_%%e_%%f" (
MD %%b_%%c_%%d_%%e 2>nul
MOVE "*%%b_%%c*" "%%b_%%c_%%d_%%e"
)
POPD
SET "sourcedir=U:\sourcedir\t h r e e"
PUSHD "%sourcedir%"
FOR /f %%q IN (
'dir /b /a-d "*_*-*-*-*_*_*_*.*"'
) do IF EXIST "%%q" (
FOR /f "tokens=1,2,3,4,5 delims=_" %%a IN ("%%q") DO (
MD %%b_%%c_%%d_%%e 2>nul
MOVE "*%%b_%%c*" "%%b_%%c_%%d_%%e"
)
)
POPD
GOTO :EOF
Yes - misread that you wanted to move all files containing - been up gaming all night...
The above batch is in two sections, the first using %%a..%%f and the second incorporating %%q.
The difficulty faced is that move *[pattern]* will move all of the files, as desired BUT for /f...'dir... builds a list of ALL of the matching files that were originally in the directory.
Once the first filename is processed, those other files containing the 01-PG-18-1000_NC will have been moved, so you'll get a "no files found" error on the next 01-PG-18-1000_NC file in the the list for has built.
Sure, it's possible to cruft together some mechanism for ensuring that the pattern 01-PG-18-1000_NC is only processed once, but a simple if exists for the full filename returned by for...%%a... and rebuilt can be used to gate the MD/MOVE commands as the file will no longer exist when the next 01-PG-18-1000_NC is processed (as it's already been moved). So much easier using the %%q method though.
Of course, you could also simply dispose of the error messages instead of installing a gate - but that's probably regarded as being crude.
Also aschipfl's suggestion of adding delims= to the for...%%q... is quite valid if you have separators like Space in your filenames (and costs nothing, regardless)
Oh - and I'd missed the ( in the do part in my initial response - always happens when you don't actually test the code, especially when you're tired.

Batch file for /f isnt reading files

Lots of issues With batch coding... Things just don't seem to work the way i expect them to.
So I am Using a batch file to Extract Text data from .as Files. I managed to get that working However It creates a bunch of Junk/empty txt files that don't have any useful content extracted from them. So I made another batch file that gets called from main.bat and is supposed to Clean the empty files, however the variables are incorrect even though the for loop in main.bat is almost identical.
Full Copies of the batch files main.bat and Clean.bat
The Issue Is the Bit of Code below (From Clean.bat line 33) #note the following code had most of its counters and echos removed
#echo off
cls
setlocal enabledelayedexpansion
for /r %%Z in (*.txt) do (
SET /a count=0
for /F "eol= tokens=1 delims=," %%A in ("%%Z") do (
if /i %%A==LN set /a count+=1
)
if !count! EQU 0 (
rem del "%%Z")
)
pause
In this Code %%A and %%Z Are both Equal to The Full File Path of the file that should be getting read from. When %%A should be token 1 of The txt file in question. Because of this count always = 0 so it always deletes the file (thats why del is commented out).
Here's an Example of the file its supposed to read from
LN,296,textE("海沿いに立つ高級フィットネスリゾート施設。");
LN,299,textE("夏休み、俺たち兄妹は、陸上の強化合宿という「名目」のもと、\nこの施設を訪れていた。");
LN,302,textE("莉 央\nすごい、すごい!!おしゃれなところだねー!");
Basically Its supposed to check each line and if LN doesnt Exist as the first token to any line it deletes the file. (Because that means the file is empty except for a Line count of the Original .as file)
This may work for you given the things you have said:
I interpreted your point to mean that if the file doesn't contain LN as the first token on any line, then it is to be deleted.
#echo off
for /r %%Z in (*.txt) do (
SET "count="
for /F "usebackq delims=," %%A in ("%%Z") do (
if /i "%%A"=="LN" set count=1
)
if not defined count echo del "%%Z"
)
pause
This is another way to do the same thing:
#echo off
for /r %%Z in (*.txt) do (
findstr "^LN," "%%Z" >nul || echo del "%%Z"
)
pause

Insert Into Multiple Files in Windows shell script

Basically I'm trying to write a batch file to insert some code into multiple files. Here are the details of what I'm tring to accomplish:
1. The input string comes from a file test.txt.
2. The string needs to be inserted as the second line of destination files.
3. Destination files are all the .xml files under the same direction as the batch file.
I suppose I should use a FOR loop to go through all .xml files. Something like
for /f %%i in ('dir /b *.xml') do ()
I've read though some tutorials and posts but can't find a way to add anything to files in a loop. Using Echo or TYPE doesn't seems to work for each file in a loop. How do I modify files in a loop?
Also to insert to a certain number of line some post say the file needs to be put into a variable. But my files are pretty large, which I don't want to put into variables. Is there another way to insert into a certain line in a file?
#ECHO OFF
SETLOCAL
FOR /f "delims=" %%i IN ('dir /b *.xml') DO (
SET line2=Y
(
FOR /f "usebackqdelims=" %%x IN ("%%i") DO (
ECHO(%%x
IF DEFINED line2 TYPE Line2.txt
SET "line2="
)
)>"%%~ni.lmx"
)
GOTO :EOF
This should work for you - but it will delete empty lines.
#echo off
set /P string=< test.txt
for %%a in (*.xml) do (
(for /F "usebackq tokens=1* delims=:" %%b in ('findstr /N "^" "%%a"') do (
if %%b equ 2 echo %string%
set "line=%%c"
setlocal EnableDelayedExpansion
echo(!line!
endlocal
)) > "%%a.new"
)
New files have .xml.new extension; you may add a couple lines to delete original .xml files and rename .xml.new ones to .xml.

issues with enabledelayedexpansion for file renaming batch script

i am writing a batch script monotonic file renamer. basically, it makes the titles of all the files 1 2 3 4 .... and so on. i have since expanded it to be able to handle files of different types (txt, doc, flv, etc) but not everything is working out.
my main concern is i have broken the delayed expansion calls i was making before. now using !var1! is never expanded, or never recognized as a variable.
here is a verbosely commented version of my script
::a monotonic file renamer
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET tempfile=temp.txt
SET exttemp=exttemp.txt
if [%1] == [] goto usage
::make sure your dont overwrite something useful
if EXIST %tempfile% (
ECHO Temp file already exists, are you sure you want to delete?
del /P %tempfile%
)
if EXIST %exttemp% (
ECHO EXT Temp file already exists, are you sure you want to delete?
del /P %exttemp%
)
::initialize
SET /a counter=0
SET type=
SET /a ender=%1
::write filenames to tempfile
DIR /B /ON > %tempfile%
::read lines one by one
for /f "usebackq delims=" %%a in (%tempfile%) do (
REM make sure we do not rename any of the working files
if NOT "%%a"=="renamer.bat" (
if NOT "%%a"=="temp.txt" (
if NOT "%%a"=="exttostr.bat" (
SET /a counter+=1
REM get file extension
exttostr %%a > %exttemp%
SET /P type= < %exttemp%
REM housekeeping
del /F %exttemp%
REM rename
ren %%a !counter!.!type!
ECHO Renamed "%%a" to "!counter!.!type!"
)))
REM exit when we have run enough
if "!counter!"=="!ender!" goto exit
)
goto exit
:usage
echo Usage: renamer NUMFILES
:exit
::final housekeeping
DEL temp.txt
the idea is i drop my two files, renamer.bat(this file) and exttostr.bat(helper to get the file extension) into the folder and run it, it will rename files sorted alphabetically from 1 to how ever many files i specify.
when i run the code, it never uses the variables marked for delayed expansion appropriately, always leaving them as "!varname!", so it renames the first file "!counter!.!type!" and throws errors for the rest because there is already a file in the directory with that name.
this brings me to a secondary issue. sorting the dir list alphabetically results in a poor handling of numbered files. for example the list:
"1 7 15 75 120"
is sorted:
"1 120 15 7 75"
i have not been able to find a way around this yet, only that it is indeed the intended result of the dir sort. the only workaround i have is padding numbers with enough zeroes in the front.
thanks in advance for any insight!
everything is sorted but the second problem. i think i have not spoken well. i have this issue when i take IN the directory file names, not when writing out. so they already need to be padded. i has hoping there was some other way to read the directory and have it be sorted appropriately.
the most promising thing i have found is here: http://www.dostips.com/DtCodeBatchFiles.php#Batch.SortTextWithNumbers
#ECHO OFF
if "%~1"=="/?" (
echo.Sorts text by handling first number in line as number not text
echo.
echo.%~n0 [n]
echo.
echo. n Specifies the character number, n, to
echo. begin each comparison. 3 indicates that
echo. each comparison should begin at the 3rd
echo. character in each line. Lines with fewer
echo. than n characters collate before other lines.
echo. By default comparisons start at the first
echo. character in each line.
echo.
echo.Description:
echo. 'abc10def3' is bigger than 'abc9def4' because
echo. first number in first string is 10
echo. first number in second string is 9
echo. whereas normal text compare returns
echo. 'abc10def3' smaller than 'abc9def4'
echo.
echo.Example:
echo. To sort a directory pipe the output of the dir
echo. command into %~n0 like this:
echo. dir /b^|%~n0
echo.
echo.Source: http://www.dostips.com
goto:EOF
)
if "%~1" NEQ "~" (
for /f "tokens=1,* delims=," %%a in ('"%~f0 ~ %*|sort"') do echo.%%b
goto:EOF
)
SETLOCAL ENABLEDELAYEDEXPANSION
set /a n=%~2+0
for /f "tokens=1,* delims=]" %%A in ('"find /n /v """') do (
set f=,%%B
(
set f0=!f:~0,%n%!
set f0=!f0:~1!
rem call call set f=,%%%%f:*%%f0%%=%%%%
set f=,!f:~%n%!
)
for /f "delims=1234567890" %%b in ("!f!") do (
set f1=%%b
set f1=!f1:~1!
call set f=0%%f:*%%b=%%
)
for /f "delims=abcdefghijklmnopqrstuwwxyzABCDEFGHIJKLMNOPQRSTUWWXYZ~`##$*_-+=:;',.?/\ " %%b in ("!f!") do (
set f2=00000000000000000000%%b
set f2=!f2:~-20!
call set f=%%f:*%%b=%%
)
echo.!f1!!f2!!f!,%%B
rem echo.-!f0!*!f1!*!f2!*!f!*%%a>&2
)
this code can sort the filenames with one number in them (i.e. video100.mov is fine, video100video10.mov would break it)
the issue i have is i think adding a call to this helper fn will break it again, so i will be trying to include this in my modified renamer.bat now. any help is appreciated.
Probably the batch for extracting the extension reset the local environment.
But, you don't need it. You may extract the extension with the ~x option. Something similar to this ....
:monotonicrename
set /a counter = 0
for %%a in (%1\*.*) do (
if exist %%~fa (
set /a counter += 1
echo ren %%~fa !counter!%%~xa
)
)
goto :eof
to include leading zeroes in the counter, so that the directory sorts correctly, replace the previous rename command with three lines
set zcounter=0000!counter!
set zcounter=!zcounter:~-4!
echo ren %%~fa !counter!%%~xa
So putting all pieces together, add the monotonicrename function you just created in the batch file that can be as simpler as...
#echo off
setlocal enabledelayedexpansion
call :monotonicrename %1
goto :eof
:monotonicrename
set /a counter = 0
for %%a in (%1\*.*) do (
if exist %%~fa (
set /a counter += 1
set zcounter=0000!counter!
set zcounter=!zcounter:~-4!
echo ren %%~fa !zcounter!%%~xa
)
)
goto :eof
I didn't experience any issues with delayed expansion, everything worked fine for me (except, of course, for the fact that I didn't have the exttostr.bat helper script.)
Anyway, there are several things that could be improved about your script:
You don't need to store the result of DIR into a file to read it afterwards. You can read the output directly in the FOR loop.
You don't need the helper batch script. The extension can be extracted from %%a by using the ~x modifier with the loop variable: %%~xa. You can read more about modifiers by issuing HELP FOR from the command prompt.
The renamer batch file's own name can be referenced in the script as %0. You can apply the ~n modifier where you only need to use the name without the extension. The combined modifier of ~nx will give you the name with the extension.
So, here's how your script might look like with the above issues addressed:
::a monotonic file renamer
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
IF [%1] == [] GOTO usage
::initialize
SET /A counter=0
SET type=
SET /A ender=%1
::read lines one by one
FOR /F "usebackq delims=" %%a IN (`DIR /B /ON`) DO (
REM make sure we do not rename any of the working files
IF NOT "%%~a"=="%~nx0" (
SET /A counter+=1
RENAME "%%~a" "!counter!%%~xa"
ECHO Renamed "%%~a" to "!counter!%%~xa"
)
REM exit when we have run enough
IF "!counter!"=="!ender!" GOTO :EOF
)
GOTO :EOF
:usage
ECHO Usage: %~n0 NUMFILES
As for your secondary issue, it can be easily resolved like this:
Use something like 100000 as counter's initial value. (Use however many 0s you like, but possibly no more than nine.) Add the same value to ender as well.
When renaming files, instead of !counter! use the expression that removes the first character (the 1): !counter:~1! (in fact, this is not about removal, but about extracting a substring starting from the offset of 1, learn more about it with the HELP SET command).
Here's the modified version of the above script:
::a monotonic file renamer
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
IF [%1] == [] GOTO usage
::initialize
SET /A counter=1000
SET type=
SET /A ender=%1
SET /A ender+=counter
::read lines one by one
FOR /F "usebackq delims=" %%a IN (`DIR /B /ON`) DO (
REM make sure we do not rename any of the working files
IF NOT "%%~a"=="%~nx0" (
SET /A counter+=1
RENAME "%%~a" "!counter:~1!%%~xa"
ECHO Renamed "%%~a" to "!counter:~1!%%~xa"
)
REM exit when we have run enough
IF "!counter!"=="!ender!" GOTO :EOF
)
GOTO :EOF
:usage
ECHO Usage: renamer NUMFILES
You can also see that I made some other enhancements, like making sure the file name is enclosed in double quotes, and using GOTO :EOF instead of GOTO exit (:EOF is a special pre-defined label that points at the end of the batch script so you don't need to define your own).

Resources