Batch, read filename backwards - windows

I'm working on a little script that moves files to a different map sorted by the last 2 characters, now my problem is, files always look like this:
1238184AD
1237135881AD
123477TG
And my problem here is, I can move files to the correct map if they have a fixed length, but they are not fixed. Sow now my question is, can I count the filename backwards so that the script will make a directory of the last 2 characters.
This is how my current script looks like:
#ECHO OFF
setlocal enabledelayedexpansion
set index=~8,2
set moveFrom=C:\Users\**\Desktop\Map\
set moveTo=C:\Users\**\Desktop\Map2\
for /R "%moveFrom%" %%f in (*.txt) do (
echo %%f
set "fileName=%%~nf"
cd %moveTo%
IF EXIST "!fileName:%index%!" (
move /-y "%%f" "%moveTo%"!fileName:%index%!"\"
echo "%%f" moved
) ELSE (
mkdir "!fileName:%index%!"
move /-y "%%f" "%moveTo%"!fileName:%index%!"\"
echo "%%f" moved
)
)
pause

Related

Find in file then move the file

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.

compressing multiple files into bzip2

so i found this nice batch for window that would compress every file of the same extension in the same directory into bzip2 by dragging and dropping any of the files into it but i would like to take it further and make it that when i drag and drop a folder into it. it would compress all the files in it, including the sub-folders until it reaches the end. obviously i would guess it has something to do with looping with using %%d but i could not exactly figure it out.
#echo off
if [%1]==[] goto usage
for /f %%i in ("%1") do (
echo %%~di
echo %%~pi
echo %%~xi
set rootpath="%%~di%%~pi*%%~xi"
)
for %%f in (%rootpath%) do (
"C:\Program Files\7-Zip\7z.exe" a -tbzip2 "%%f.bz2" "%%f" -mx9
del "%%f" /s /f /q
)
echo Finished operations!
goto exit
:usage
echo You have to drag and drop a file on this batch script!
echo Sorry for the poor documentation, but if you'll want to use it, you have to edit the .bat file
echo The only thing you really need is to change the path to your 7-Zip installation
echo Then simply drag and drop a file in a folder you want to BZip2, and it'll do the rest automatically
:exit
pause
I share with you this helpful and well commented batch script posted by enteleform on superuser
I just modified this variable Set archivePath="%%~x.zip" to Set archivePath="%%~x.bz2"
How to make 7-zip do a whole bunch of folders
#Echo OFF
SetLocal EnableDelayedExpansion
Rem // 7-Zip Executable Path
Set sevenZip="C:\Program Files\7-Zip\7z.exe"
Rem // START: NewLine Variable Hack
Set newLine=^
Rem // END: NewLine Variable Hack !! DO NOT DELETE 2 EMPTY LINES ABOVE !!
Rem // Set ErrorLog Variables
Set errorCount=0
Set separator=--------------------------------------------------------
Set errorLog=!newLine!!newLine!!separator!!newLine!!newLine!
Set errorPrefix=ERROR #:
Set successMessage=All Files Were Successfully Archived
Rem // Loop Through Each Argument
SetLocal DisableDelayedExpansion
for %%x in (%*) do (
Rem // Use Current Argument To set File, Folder, & Archive Paths
SetLocal DisableDelayedExpansion
Set filePath="%%~x"
Set directoryFiles="%%~x\*"
Set archivePath="%%~x.bz2"
SetLocal EnableDelayedExpansion
Rem // Source Is A Folder
if exist !directoryFiles! (
Set sourcePath=!directoryFiles!
)
Rem // Source Is A File
if not exist !directoryFiles! (
Set sourcePath=!filePath!
)
Rem // Print Separator To Divide 7-Zip Output
echo !newLine!!newLine!!separator!!newLine!!newLine!
Rem // Add Files To Zip Archive
!sevenZip! A -TZIP !archivePath! !sourcePath!
Rem // Log Errors
if ErrorLevel 1 (
Set /A errorCount=errorCount+1
Set errorLog=!errorLog!!newLine!!errorPrefix!!sourcePath!
)
)
Rem // Print ErrorLog
if !errorCount!==0 (
Set errorLog=!errorLog!!newLine!!successMessage!
)
Echo !errorLog!!newLine!!newLine!!newLine!
Rem // Keep Window Open To View ErrorLog
pause
You could probably do that with a single line batch-file:
#For %%G In ("%~1")Do #If "%%~aG" GEq "d" (For /F Delims^= %%H In ('""%__AppDir__%where.exe" /R "%%~G" * 2>NUL|"%__AppDir__%findstr.exe" /EVIL ".bz2""')Do #"%ProgramFiles%\7-Zip\7z.exe" a -tbzip2 "%%~dpH%%~nH.bz2" "%%H" -mx9 -sdel -w >NUL 2>&1)&"%__AppDir__%timeout.exe" /T 3
If you'd like it over multiple lines for readability:
#For %%G In ("%~1") Do #If "%%~aG" GEq "d" (
For /F "Delims=" %%H In (
'""%__AppDir__%where.exe" /R "%%~G" * 2>NUL | "%__AppDir__%findstr.exe" /EVIL ".bz2""'
) Do #"%ProgramFiles%\7-Zip\7z.exe" a -tbzip2 "%%~dpH%%~nH.bz2" "%%H" -mx9 -sdel -w >NUL 2>&1
"%__AppDir__%timeout.exe" /T 3
)
These examples should only work if you drag and drop a directory onto it, or call it on the command line with a directory as the first argument.
#echo off
for /f %%i in ("%1") do (
echo %%~di
echo %%~pi
echo %%~xi
set rootpath="%%~di%%~pi*%%~xi"
)
for /R %%f in (*) do (
"C:\Program Files\7-Zip\7z.exe" a -tbzip2 "%%f.bz2" "%%f" -mx9 -x!"packall.bat"
del "%%f" /s /f /q
)
echo Finished operations!
goto exit
:usage
echo You have to drag and drop a file on this batch script!
echo Sorry for the poor documentation, but if you'll want to use it, you have to edit the .bat file
echo The only thing you really need is to change the path to your 7-Zip installation
echo Then simply drag and drop a file in a folder you want to BZip2, and it'll do the rest automatically
:exit
pause
Cheers to my friend Anya who found a solution, so the way it would work with the script above is that you make a batch file name it packall.bat
save it anywhere as it will delete itself at the end of the process.
when you want to compress bunch of files into bz2 you copy it and put it in inside a folder made with any name in your desktop.
make sure its name has no spaces nor its sub-folders as that may confuse batch and make it compress your desktop contents for some reason.
click on the batch, then it will compress all the files within the same folder its in and their sub-folders and automatically delete itself.
Video example:
http://billstuff.site.nfoservers.com/e79nwk69.mp4
IMPORTANT NOTE for some reason if there duplicate names of files with the same extension at sub-folders they will be deleted
Don't forget the folder and its sub-folder names should not have a space
Best of luck!

DOS batch file For loop runs twice

I have a batch file that recursively encodes videos to a sub folder "encode" then deletes the original and moves the new file to the original directory. The problem I'm having is that after each video is encoded, the for loop picks up the newly encoded video and runs again. After that, it moves on to the next video. I'm not sure why it runs twice instead of once or infinitely. What am I misunderstanding? I am a complete novice, so my apologies if it's a simple mistake.
#echo off
set /A count = 0
pushd %~dp0
for /R %%f in (*.mp2, *.mpg, *.vob, *.avi, *.wmv, *.mov, *.mp4, *.m4v, *.mpeg) do (
mkdir %%~dpf\encode
C:\HandBrakeCLI -i "%%f" -o "%%~dpf\encode%%~nf.mp4"
del "%%f"
move "%%~dpf\encode\%%~nf.mp4" %%~dpf
rmdir %%~dpf\encode
set /A count+=1
)
popd
echo Count is: %count%
pause
The reason it processes twice is because the file conversion creates another video clip that matches the criteria in the FOR loop.
To avoid dealing with folder structures and syncing, a simple way to get around this is to split the process into two loops, performing the *.mp4 files first:
#echo off
set /A count = 0
pushd %~dp0
for /R %%f in (*.mp4) do (
mkdir %%~dpf\encode
C:\HandBrakeCLI -i "%%f" -o "%%~dpf\encode%%~nf.mp4"
del "%%f"
move "%%~dpf\encode\%%~nf.mp4" %%~dpf
rmdir %%~dpf\encode
set /A count+=1
)
for /R %%f in (*.mp2, *.mpg, *.vob, *.avi, *.wmv, *.mov, *.m4v, *.mpeg) do (
mkdir %%~dpf\encode
C:\HandBrakeCLI -i "%%f" -o "%%~dpf\encode%%~nf.mp4"
del "%%f"
move "%%~dpf\encode\%%~nf.mp4" %%~dpf
rmdir %%~dpf\encode
set /A count+=1
)
popd
echo Count is: %count%
pause
Don't forget to remove the *.mp4 from the second loop's file list.
Edit: Here's a solution that's more elegant.
#echo off
set /A count = 0
pushd %~dp0
for %%e in (mp4 mp2 mpg vob avi wmv mov m4v mpeg) do (
for /R %%f in (*.%%e) do (
mkdir %%~dpf\encode
C:\HandBrakeCLI -i "%%f" -o "%%~dpf\encode%%~nf.mp4"
del "%%f"
move "%%~dpf\encode\%%~nf.mp4" %%~dpf
rmdir %%~dpf\encode
set /A count+=1
)
)
popd
echo Count is: %count%
pause
Make sure the mp4 is listed first so it's not reconverted once the other file types are processed.
I've tested it to see why it behaves so strangely like this, well, and the only answer I could come up with is that it simply acts strangely. my guess is that it depends on the order of operations.
this is my take on it:
in some implementations of the code, the for /r avoids an infinite loop. what it does, is run on the files that are not .mp4 first. then, probably because it was renamed, it doesn't recognize it as the same file.
probably, after it runs on the .mp4, the second time, it's file inode (except for the last time opened and edited) shouldn't be different at least to the point where the system won't recognize it as the same file anymore.
I tested a bit different version of the code that did produce an infinite loop:
set /A count = 0
pushd %~dp0
for /R %%f in (*.mp2, *.mpg, *.vob, *.avi, *.wmv, *.mov, *.mp4, *.m4v, *.mpeg) do (
mkdir %%~dpf\encode
move %%f %%~dpf\encode
rename %%~dpf\encode\%%f %%~dpf\encode\%%~nf.mp4
move %%~dpf\encode\%%~nf.mp4 %%~dpf
rmdir %%~dpf\encode
set /A count+=1
)
popd
echo Count is: %count%
pause
and strangely, not only it ran an infinite loop, but it also created an infinite amount of subfolders named '\encode\encode\encode...', but the reason for that doesn't matter.
what's different in this version of the code, is that I always rename the files.
that is probably why it produces an infinite loop.
the for /r command reiterates files that have been renamed, and not necessarily on those edited.
the solution seems to be, indeed, to run the code on all .mp4 files first, and the other ones second.

Batch script - dynamic/variable paths in loop

My requirement is to write a batch script to find and replace the a string in all of the *-spec.js files in given set of directories. Hence I have written the batch file and running the batch script as below.
<script file name> <search_string> <replace_string> <folder_path_1> <folder_path_2> <folder_path_n>
(I am sure the folder_path_n will not go beyond 7)
e.g C:\CI\Scripts>replace.bat hello world C:\app\e2e C:\sppa\e2e
So my script is as below.
#echo off
setlocal enabledelayedexpansion
set argCount=0
for %%x in (%*) do (
set /A argCount+=1
set "argVec[!argCount!]=%%~x"
)
set search=%1
set replace=%2
echo Search is %search%
echo Replace is %replace%
for /L %%i in (3,1,%argCount%) do (
set path=!argVec[%%i]!
echo path is !path!
for /R !path! %%F in (*spec.js) do (
echo %%F
)
)
Here it prints the 4 arguments correctly even the path is also printed as expected. In the next step it's expected to loop through the given path and gets all of the files that ends with "spec.js".
e.g not working:
for /R !path! %%F in (*spec.js) do (
echo %%F
)
But it prints nothing. Instead if the variable is replaced with hard coded value, it works as expected.
e.g - working:
for /R C:\app\sppa\e2e %%F in (*spec.js) do (
echo %%F
)
Your help is highly appreciated!
The reason it's not working is that the variable content must be known when the loop is parsed means that it only works with variables that can be expanded without delayed expansion. Nevertheless there is an easy solution as a for /r loop is working with the current path (from ss64).
If the [drive:]path are not specified they will default to the current drive:path.
Just change directory to !path! and then go back:
rem Change into !path! and remember directory coming from
pushd !path!
for /R %%F in (*spec.js) do (
echo %%F
)
rem Change back to origin
popd
I also tried similar as suggested by #Andre Kampling as below.
cd !path!
::echo Changed the path to !path!
FOR /R %%F IN (*spec.js) DO (
echo %%F
)

Batch script to remove parentheses and spaces from all file names

I have to manipulate dozens if not hundreds of images fairly often. When I get the images, it's often 1018u182012480d1j80.jpg type filenames, so I can select all of the images, and then hit 'F2' to rename them all to image (1).jpg | image (2).jpg | ... etc. Can someone write me a batch script to remove the parentheses and the spaces in the file names?
If possible, it'd be great if I didn't even have to open it up and edit the batch file to update the current dir, I.E, if it can just use %CD% or something to get the current folder, that would be awesome.
I don't understand batch files at all but here's one I found that will remove the parentheses, but I have to add the sourcedir.
#ECHO OFF
SETLOCAL
SET "sourcedir=C:\.." #Can we make this just find the location?
FOR /f "delims=" %%a IN (
'dir /b /s /a-d "%sourcedir%\*" '
) DO (
SET "name=%%~na"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "newname=!name:)=!"
SET "newname=!newname:(=!"
IF "!name!" neq "!newname!" (
IF EXIST "%%~dpa!newname!%%~xa" (ECHO cannot RENAME %%a
) ELSE (REN "%%a" "!newname!%%~xa")
)
endlocal
)
The script should work if file names/paths does not contain any ! exclamation mark.
Supply a folder path as an argument (see sample calls below). This can be done even by file explorer's drag&drop feature (drag a folder, drop on batch). Read call /? or Command Line arguments (Parameters) for %~1 explanation.
Narrow to only .jpg files using "%sourcedir%\*.jpg" in FOR /f line.
#ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
SET "sourcedir=%~1" supplied string
if NOT defined sourcedir SET "sourcedir=%CD%" current directory if nothing supplied
rem basic validity check
if NOT exist "%sourcedir%\*" (
echo wrong directory "%sourcedir%"
goto :next
)
FOR /f "delims=" %%a IN ('dir /b /s /a-d "%sourcedir%\*" ') DO (
SET "name=%%~na"
SETLOCAL ENABLEDELAYEDEXPANSION
rem remove ) right parenthesis
SET "newname=!name:)=!"
rem remove ( left parenthesis
SET "newname=!newname:(=!"
rem remove ↓ space(s)
SET "newname=!newname: =!"
IF "!name!" neq "!newname!" (
IF EXIST "%%~dpa!newname!%%~xa" (
ECHO cannot RENAME %%a
) ELSE (
rem operational RENAME command is merely ECHO-ed for debugging purposes
ECHO RENAME "%%a" "!newname!%%~xa"
)
)
ENDLOCAL
)
:next
rem pause to see output
pause
Sample call without argument - applies to the current directory:
d:\bat\SU> D:\bat\SO\43097467.bat
RENAME "d:\bat\SU\New Text Document.txt" "NewTextDocument.txt"
RENAME "d:\bat\SU\Files\ruzna pisma.png" "ruznapisma.png"
RENAME "d:\bat\SU\Files\volume control options.png" "volumecontroloptions.png"
RENAME "d:\bat\SU\Files\volume mixer.png" "volumemixer.png"
RENAME "d:\bat\SU\Files\1126981\ERKS 100004_thumb.jpg" "ERKS100004_thumb.jpg"
Press any key to continue . . .
Sample call with argument - applies to the supplied directory:
d:\bat\SU> D:\bat\SO\43097467.bat D:\test\43097467
RENAME "D:\test\43097467\image do - Copy (2).bmp" "imagedo-Copy2.bmp"
cannot RENAME D:\test\43097467\image do - Copy (3).bmp
RENAME "D:\test\43097467\image do - Copy (4).bmp" "imagedo-Copy4.bmp"
Press any key to continue . . .
Sample call, argument with spaces must be enclosed in a pair of double quotes:
d:\bat\SU> D:\bat\SO\43097467.bat "D:\bat\odds and ends\a b"
RENAME "D:\bat\odds and ends\a b\c d\my list_Utf8.txt" "mylist_Utf8.txt"
RENAME "D:\bat\odds and ends\a b\c d\e f\h i batch.bat" "hibatch.bat"
RENAME "D:\bat\odds and ends\a b\c d\e f\System locale.png" "Systemlocale.png"
Press any key to continue . . .
d:\bat\SU>

Resources