I'm trying to find files that do not match (at the beginning of the filename) predefined formats contained in a .txt file.
I have the following:
#Echo off
chcp 1254>nul
setlocal DisableDelayedExpansion
for /f "usebackq tokens=1,2,3* delims=~" %%f in ("%USERPROFILE%\Desktop\xref.txt") do (
set "DIRNAME=%%f"
set "DIRNAM2=^%%f"
set "PATHNAM=%%h"
set "ALBUMNM=%%g"
SETLOCAL EnableDelayedExpansion
IF EXIST !PATHNAM!!DIRNAME! (
PushD !PATHNAM!!DIRNAME!
dir /b /a-d "*" | findstr /v /r /c:"!DIRNAM2! -*"
)
ENDLOCAL
)
pause
EXIT /b
This works great except with filenames containing bangs (exclamation points).
Here's a sampling of my .txt file (subdirectory~album name~path) which gets generated by a script:
12 Byzantine Rulers. The History of The Byzantine Empire~12 Byzantine Rulers. The History of The Byzantine Empire~g:\test\
17th Century Poetry~17th Century Poetry~g:\test\
1984 (George Orwell)~1984 (George Orwell)~g:\test\
1_2_1~1_2_1~g:\test\
21st Century American Foreign Policy~21st Century American Foreign Policy~g:\test\
99% Invisible~99% Invisible~g:\test\
Communication Matters. That’s Not What I Meant!~Communication Matters. That’s Not What I Meant!~g:\test\
There are hundreds of directories containing hundreds of files (podcasts). I'd like to fix this batch so it can also handle bangs (!).
Thx in advance.
Edit. My test data wasn't robust enough. The findstr command also doesn't work with (at least) the following characters: é’»¿ ... that is to say PushD gets me to the right directory, but FindStr doesn't do it's culling as expected.
I don't think that the issue is necessarily code page or encoding related, and less so exclamation marks, (bangs). The major issue I see is that your text file content uses smart quotes, (curly), instead of dumb quotes, (straight). Additionally you have % characters which in batch files usually require doubling. For those reasons I would first suggest that you try to replace those characters.
For example:
#Echo Off
SetLocal DisableDelayedExpansion
For /F "UseBackQ Tokens=1-3 Delims=~" %%G In ("%USERPROFILE%\Desktop\xref.txt")Do (
Set "SUBDIRN=%%G"
Set "ALBUMNM=%%H"
Set "PATHNAM=%%I"
SetLocal EnableDelayedExpansion
Set SUBDIRN=!SUBDIRN:%%=%%%%!
Set ALBUMNM=!ALBUMNM:%%=%%%%!
Set PATHNAM=!PATHNAM:%%=%%%%!
Set SUBDIRN=!SUBDIRN:’='!
Set ALBUMNM=!ALBUMNM:’='!
Set PATHNAM=!PATHNAM:’='!
Set SUBDIRN=!SUBDIRN:“="!
Set ALBUMNM=!ALBUMNM:“="!
Set PATHNAM=!PATHNAM:“="!
Set SUBDIRN=!SUBDIRN:”="!
Set ALBUMNM=!ALBUMNM:”="!
Set PATHNAM=!PATHNAM:”="!
If Exist "!PATHNAM!!SUBDIRN!\" (
PushD "!PATHNAM!!SUBDIRN!"
Dir /B/A-D|FindStr /IVRC:"^!SUBDIRN! -"
)
EndLocal
)
Pause
Exit /B
I'm not sure how a copy of this code, within the code box will handle the smart quotes, but I'm sure you'll get the idea.
Related
This is my continuing attempt to build a filename format verification batch routine (batch variable exclamation points used in dir | findstr)
Here's where I'm at:
echo off
REM Ensure filenames are of the format ALBUM - TITLE
chcp 1254>nul
setlocal DisableDelayedExpansion
set /p CUTOFFDATE=Enter the Date of the Last Cleanup (yyyymmdd):
for /r "\\kodi-pc\g\itunes\iTunes Media\Podcasts\American Civil War\" %%i in (*.mp3) do (
set "FILENAME=%%~nxi"
set "FILEDATE=%%~ti"
call set "TITLE=%%FILENAME:* - = - %%"
call:SETALBUM
call set "FILEDATE=%%FILEDATE:~6,4%%%%FILEDATE:~0,2%%%%FILEDATE:~3,2%%"
setlocal EnableDelayedExpansion
if !FILEDATE! GTR !CUTOFFDATE! (
echo ~ALBUM~TITLE~FILENAME~ ~!ALBUM!~!TITLE!~!FILENAME!
)
endlocal
)
pause
exit /b
:SETALBUM
call set "ALBUM=%%FILENAME:%TITLE%=%%"
exit /b
Works great except where folder names contain non-ASCII characters (», ’, etc.). My effort has been to recognize bangs (!) but that accomplished I now have these other problems.
The foldername 'American Civil War' is merely a sample placeholder for this forum. In reality I loop through many hundreds of foldernames.
Thx.
I have a folder with photos that has more sub-folders which have dates as name.
For instance it is something like C:\Users\Lorem\Desktop\Photos\22-Dec-98\.
And inside each date folder I have photos that have short descriptions, e.g Third morning on site.png, but some may contain exclamation marks (!).
I managed, by looking at other questions, to come up with a program that adds the date in front of each short description, e.g. 18-Jun-98-Weekend campfire.png, which is what I wanted, but it fails to do so when the short description has an exclamation mark.
#echo OFF
SET /P folderPath="Enter full path of the folder which has the files you want to rename: "
PAUSE
SETLOCAL EnableDelayedExpansion
PAUSE
FOR /F "tokens=*" %%G IN ('dir /b %folderPath%') DO (call :subroutine "%%G")
PAUSE
:subroutine
set date=%1
set date=%date:~1,-1%
set newPath=%folderPath%\%date%\
FOR /F "tokens=*" %%F IN ('dir /b %folderPath%\%1\') DO (call :rename "%%F")
:rename
set fileName=%1
set fileName=%fileName:~1,-1%
set name=%date%-%fileName%
set noname=%newPath%%date%
REN "%noname%" "%name%"
I know the approach that requires input of the folder location is probably not the best option but it was the best workaround I could come up with. All in all, what should I change in/add to my code for it to rename files that contain exclamation marks as well? I would highly appreciate explanations to any changes, if possible, since I am not all that knowledgeable about batch scripting; I only adapted code from different questions/answers. Also I really fail to completely understand what %1 and %%F mean or hold as values so any link to tutorials/short explanation are welcome.
Thanks in advance!
I have many files in many folders that I need to rename.
And example is
from cgs2016-09-05-05-40-34.xls
to cgs0905.xls
and
from cgs2016-09-06-05-40-34
to cgs0906.xls
etc
Any help would be greatly appreciated!
#Jamaz Try out the following code below on a sample of your files. Again please use it on a test sample of your files so it does not cause you issues if it makes a mistake. Thank you and please up-vote if this works for you.
setlocal enabledelayedexpansion
REM Collect list of file names in current directory that have the .xls file extension. Output to text file.
dir /b "*.xls" >xls.txt
REM For loop examines the text file for individual file names.
FOR /F "tokens=1" %%# in (.\xls.txt) do (
REM SET variable "#" to equal "token"
Set "token=%%#"
REM Extract the first 3 characters (year) from the file name and set is to variable "token"
Set "tokenchar=!token:~0,3!"
REM Extract the month characters from the file name and set the variable as "tokenmonth"
Set "tokenmonth=!token:~8,2!"
REM Extract the day characters from the file name and set the variable as "tokenday"
Set "tokenday=!token:~11,2!"
ren "%%#" "!tokenchar!!tokenmonth!!tokenday!.xls"
echo %%#
)
Pause
not the best way, but works for your examples:
#echo off
setlocal enabledelayedexpansion
for %%x in (*.xls) do (
set "filename=%%x"
ECHO ren "%%x" "!filename:~0,3!!filename:~8,2!!filename:~11,2!.xls"
)
remove the ECHO if output is ok.
Because the last nineteen characters, date and time stamp, are more likely to be constant than the first three, (especially over multiple folders), I'd change both the previous answers to cater for that rationale.
#Echo Off
SetLocal EnableDelayedExpansion
(Set _rf=C:\Users\jamaz\TestDir)
(Set _fe=xls)
If Not Exist "%_rf%\" Exit/B
For /R "%_rf%" %%I In (*.%_fe%) Do (Set "_fn=%%~nI"
Echo=Ren "%%I" "!_fn:~,-19!!_fn:~-14,2!!_fn:~-11,2!%%~xI")
Timeout -1 1>Nul
EndLocal
Exit/B
As the OP was not clear about whether the code was for multiple same level folders or subfolders rooted from a single location, I went for the latter as the previous responses had already covered that.
Change your chosen file path and extension on lines 4 and 5
If you are happy with the console output, remove echo= from line 10 and delete line 11
I'm trying to rename .jpg files which is in one of many subdirectories of e:\study\pubpmc\test\extracted.
I want to rename files to LastFolderName_ImageName.jpg.
(For example if Figure1.jpg is in e:\study\pubpmc\test\extracted\folder1
I want it to be renamed like this: folder1_Figure1.jpg)
So I need to take out the last folder name from the file's path.
Since it's my first time with batch scripting, I'm having a hard time.
I googled and made code similar to it
but it doesn't seem to work out.
Can you help me with it and tell me where I've done wrong?
Thank you! :)
#echo off
cd /D "e:\study\pubpmc\test\extracted"
for /r %%f in (*.jpg) do (
set mydir=%%~dpf
set mydir=%mydir:\=;%
for /f "tokens=* delims=;" %%i in (%mydir%) do call :LAST_FOLDER %%i
goto :EOF
:LAST_FOLDER
if "%1"=="" (
#echo %LAST%
goto :EOF
)
set LAST=%1
SHIFT
goto :LAST_FOLDER
)
JosefZ explains the obvious problems with your code, but he failed to point out a subtle problem, though his code fixed it:
FOR /R (as well as the simple FOR) begin iterating immediately, before it has finished scanning the disk drive. It is possible for the loop to reiterate the already named file! This would cause it to be renamed twice, giving the wrong result. The solution is to use FOR /F with command 'DIR /B', because FOR /F always processes the command to completion before iterating.
JosefZ also provides code that works for most situations. But there is a much simpler solution that works always:
#echo off
for /f "delims=" %%A in (
'dir /b /s /a-d "e:\study\pubpmc\test\extracted\*.jpg"'
) do for %%B in ("%%A\..") do ren "%%A" "%%~nxB_%%~nxA"
The "%%A\.." treats the file name as a folder and walks up to the parent folder. So %%~nxB gives the name of the parent folder.
The command could be run as a long one liner, directly from the command line (no batch):
for /f "delims=" %A in ('dir /b /s /a-d "e:\study\pubpmc\test\extracted\*.jpg"') do #for %B in ("%A\..") do #ren "%A" "%~nxB_%~nxA"
Avoid using :label and :: label-like comment inside (command block in parentheses). Using any of them within parentheses - including FOR and IF commands - will break their context.
Using variables inside (command block in parentheses). Read EnableDelayedExpansion: Delayed Expansion will cause variables to be expanded at execution time rather than at parse time [and CLI parses all the (command block in parentheses) at once]
Next script should work for you. Note rename statement is merely echoed for debugging purposes.
#ECHO OFF >NUL
SETLOCAL enableextensions disabledelayedexpansion
set "fromFolder=e:\study\pubpmc\test\extracted"
rem my debug setting set "fromFolder=D:\path"
for /F "tokens=*" %%f in ('dir /B /S /A:D "%fromFolder%\*.*"') do (
set "mydir=%%~ff"
set "last=%%~nxf"
call :renameJPG
)
#ENDLOCAL
goto :eof
:renameJPG
rem echo "%mydir%" "%last%"
for /f "tokens=*" %%i in ('dir /B /A:-D "%mydir%\*.jpg" 2^>nul') do (
echo ren "%mydir%\%%~nxi" "%last%_%%~nxi"
)
goto :eof
Resources:
SETLOCAL, disableDelayedExpansion, ENDLOCAL etc.
An A-Z Index of the Windows CMD command line
Windows CMD Shell Command Line Syntax
I already wrote a function for that. You give it any path and it returns you only it's filename or pathname. Works for any path: Url, Windows path, Linux path, etc...
Copy this function at the end of your batch script: (Instructions below)
rem ===========================================================================
:Name_From_Path
SetLocal
set _TMP_FOLDERNAME=%1
for %%g in ("%_TMP_FOLDERNAME%") do set _TMP_FOLDERNAME=%%~nxg
EndLocal & set _Name_From_Path=%_TMP_FOLDERNAME%
goto :EOF
rem ===========================================================================
Usage:
CALL :Name_Of_Path e:\study\pubpmc\test\extracted\folder1
ECHO %_Name_From_Path%
Result: folder1
If your program or com file traverses these folders when renaming, then it should be able to get the present working directory ( path ), pwd. You may be able to chop everything but the LAST_FOLDER out of this by also creating a PREVIOUS_FOLDER and doing a string replacement.
Or you may be able to break the folder names at the '\' token from the pwd into an array and use a -1 array reference to get the last folder name.
In any circumstance you'll want to check for a present working directory command.
If your creating a large text list of all these and issuing a single call to the batch file.
Then you may be better off with something like:
(Symmantic code warning )
(copy) /folderbase/some_folder/oneormore1/image_from_oneormore1.jpg (to) /folderbase/some_folder/oneormore1/oneormore1_image_from_oneormore1.jpg
Instead of copy, window uses rename, linux uses mv.
The latter example would require simply creating a duplicate list and replacing the \ with a _ while parsing through the tokens.
The code you've given is difficult to make sense of, so its hard to discern if you can simple concatenate the current folder and image name (stringify) and then write or rename them where they are.
Happy Friday Think-Tank!
I need some assistance with a Batch .BAT script. Specifically I need help with some "IF statement syntax"
I have a script that is renaming files. There are two files, one ending in four digits and the other ending in five digits. The files will be renamed with variables I have already pre-set earlier within my script.
So here is a scenario: We have two files in a directory located at
c:\Users\username\Desktop\test-dir
There are two files within test-dir:
file1.12345
file2.1234
A four digit ending is one variable type (VAR1), whereas a file ending in five digits is another variable type (VAR2).
I need an if statement to:
a) read all the files(s) with the chosen directory (without using a wildcard if possible).
b) determine based on the number of digits after the "." which variable to use.
c) once making that determination rename the file with the appropriate variables.
The final re-naming convention is as so: yyyymmddtype.1234/12345
So basically it would use the datestamp variable I already created, the type variable I already created to be injected by the if statement, and append with the original ending digits of the file.
I know this seems like a lot, but I am more so a bash script guy. I have all the elements in place, I just need the if statement and what feels like a for loop of some kind to tie it all together.
Any help would be great!
Thank you!
Sorry, not the option you where asking for. Instead of iterating over the full list checking each file for extension conformance, iterate over a list of patterns that will filter file list, renaming matching files with the asociated "type"
for %%v will iterate over variable list, for %%a will split the content of the variable in pattern and type, for %%f will generate the file list, filter with findstr using the retrieved pattern and rename matching files with the corresponding "type"
Rename command is preceded with a echo to output commands to console. If the output is correct, remove the echo to rename the files.
#echo off
rem Variables defined elsewhere
set "folder=c:\somewhere"
set "timestamp=yyyymmdd"
rem Rename pattern variables in the form pattern;type
set "var1=\.....$;type1"
set "var2=\......$;type2"
set "var1=\.[^.][^.][^.][^.]$;type1"
set "var2=\.[^.][^.][^.][^.][^.]$;type2"
setlocal enableextensions disabledelayedexpansion
for %%v in ("%var1%" "%var2%") do for /f "tokens=1,* delims=;" %%a in ("%%~v") do (
for /f "tokens=*" %%f in ('dir /a-d /b "%folder%" ^| findstr /r /c:"%%~a"') do (
echo ren "%folder%\%%~f" "%timestamp%%%~b%%~xf"
)
)
endlocal
#ECHO OFF &SETLOCAL
set "yyyymmdd=yyyymmdd"
set "VAR1=VAR1"
set "VAR2=VAR2"
for /f "delims=" %%a in ('dir /b /a-d^|findstr /re ".*\....."') do echo(ren "%%~a" "%yyyymmdd%%VAR1%%%~xa"
for /f "delims=" %%a in ('dir /b /a-d^|findstr /re ".*\......"') do echo(ren "%%~a" "%yyyymmdd%%VAR2%%%~xa"
remove echo( to get it working.
If I understand you then this will rename the two files using preset variables for each one:
for %%a in ("%userprofile%\Desktop\test-dir\*") do (
if "%%~xa"==".12345" ren "%%a" "%variableA%-%variableB%%%~xa"
) else (
ren "%%a" "%variableC%-%variableD%%%~xa"
)
)