I have a directory of academic papers that were named using the convention below:
Author1-(Year)-Title.pdf
For example,
Jones-(2011)-XXX.pdf
Smith-(2002)-YYY.pdf
Johnson-(2015)-ZZZ.pdf
I would like to rename them as
(2011)-Jones-XXX.pdf
(2002)-Smith-YYY.pdf
(2015)-Johnson-ZZZ.pdf
That is, to extract the year from the file name and put it in front.
I tried the following code, which did not work
Setlocal enabledelayedexpansion
Set "Year=2013"
Set "Replace="""
For %%a in (*.pdf) Do (
Set "NewName=(%year%)-%%~a"
Ren "%%a" "%NewName%-File:%Year%=%Replace%!"
)
Pause&Exit
In case XXX also contains hyphens I'd suggest using tokens=1,2* to stop parsing the remainder of the file name.
I'd also remove the parentheses, when the year is first place there is no need to further emphasize it.
#Echo off
for /f "tokens=1-2* delims=-()" %%A in (
'Dir /b "*-(*)-*.pdf"'
) do Ren "%%A-(%%B)-%%C" "%%B-%%A-%%C"
Sample output
> dir /b
2002-Smith-YYY.pdf
2011-Jones-XXX.pdf
2015-Johnson-ZZZ.pdf
Not tested
for /f "tokens=1,2,3 delims=-" %%a in ('dir /b "*.pdf"') do (
echo ren "%%a-%%b-%%c" "%%b-%%a-%%c"
)
this will only echo the intended rename command.If it looks ok remove the echo word.
Derived form this SO article - it works:
#ECHO OFF &SETLOCAL ENABLEDELAYEDEXPANSION
FOR %%x IN (*.pdf) DO (
FOR /f "tokens=1-3 delims=-" %%a IN ("%%~x") DO (
SET "Author=%%a"
SET "Year=%%b"
SET "Title=%%c"
ren %%x !Year!-!Author!-!Title!
)
)
Here is a reliable way of doing what you are asking for even if the author part contains - on its own. The title portion may even contain ( and ), but the author part must not. So this is the code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_FILES=.\*-(????)-*.pdf" & rem // (basic pattern to match correct files)
set "_REGEX=^[^()][^()]*-([0123456789][0123456789][0123456789][0123456789])-.*\.pdf$" ^
& rem // (precise filter to exclude files violating the demanded pattern)
if not defined _REGEX set "_REGEX=.*" & rem // (avoid trouble with empty filter)
rem // Loop through all matching files:
for /F "eol=: tokens=1,2,* delims=()" %%F in ('
dir /B /A:-D "%_FILES%" ^| findstr /I /R /C:"%_REGEX%"
') do (
rem // Store the extracted file name parts:
set "LEFT=%%F" & set "YEAR=%%G" & set "REST=%%H"
setlocal EnableDelayedExpansion
rem // Reassemble the name and rename the file:
ECHO ren "!LEFT!(!YEAR!)!REST!" "(!YEAR!)-!LEFT!!REST:*-=!"
endlocal
)
endlocal
exit /B
After having verified the correct output, remove the upper-case ECHO command to actually rename files.
Related
I have went through a lot of guides for it, but havent found a way to do something similar to lets say turn all files in folder, like these files:
djhwu4s_cat_ruhg29.png
397y_dog_j0929_ej93.png
8yhh_owl.png
into these:
_cat.png
_dog.png
_owl.png
So basically removing everything from file names but a list of predefined strings i am searching for. In example above i would define list as "_cat", "_dog", "_owl". I know that each file will have only one of these variables, and there will be only one file with each of them in folder.
Will appreciate any tips on how to achieve that. Thanks in advance!
edit:
Here is what i came up with (with stuff i can understund) and what seems to be working fine now.
#echo off
setlocal enabledelayedexpansion
set v1=_cat-cat
set v2=_cat-owl
set v3=_cat
set v4=_dog
set v5=_owl
set v6=_horse
FOR /L %%a IN (1,1,6) DO (
rem echo %%a
rem echo !v%%a!
FOR /f %%f in ('dir /b /a:-D *!v%%a!.*') DO (
REN %%f !v%%a!.*
)
FOR /f %%f in ('dir /b /a:-D *!v%%a!_*.*') DO (
REN %%f !v%%a!.*
)
)
rem using two passes of this simpler code i can grasp and understund with dot and with underscore
rem after constructed variables value i make sure cat-cat is not recognised as and renamed to cat
rem no matter if im getting file with that variable as the last string before extension or another underscore
rem Gonna test it in combat now
For some reason this stuff doesnt work with files containing spaces and characters like:
"ab’c efg_dog.png"
FOR /L %%a IN (1,1,36) DO (
FOR /f %%f in ('dir /b /l /a:-D *!v%%a!.*') DO (
REN "%%f" "!v%%a!.*"
)
FOR /f %%f in ('dir /b /l /a:-D *!v%%a!_*.*') DO (
REN "%%f" "!v%%a!.*"
)
)
After further testing i have realised the problem starts with the %%f, and not the REN function as i thought. echo %%f before ren gives just the first part of the name to the first space, hence the REN function cant find the file. In case of "ab’c efg_dog.png" after finding the file with dir, the %%f becomes just "ab’c".
edit: After more tests and experiments and adding those "delims" to the code, the echo now shows proper, full names to be renamed, but it replaces that weird ’ character with ' for the REN command and thats why it still cant find the file to rename.
FOR /L %%a IN (1,1,36) DO (
FOR /f "delims=" %%f in ('dir /b /l /a:-D *!v%%a!.*') DO (
echo %%f
echo REN "%%f" "!v%%a!.*"
)
FOR /f "delims=" %%f in ('dir /b /l /a:-D *!v%%a!_*.*') DO (
echo %%f
echo REN "%%f" "!v%%a!.*"
)
)
#ECHO OFF
SETLOCAL
rem The following setting for the directory is a name
rem that I use for testing and deliberately includes spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
PUSHD "%sourcedir%"
FOR /f "delims=" %%e IN ('dir /b /a-d "*_*" 2^nul ^|findstr /v /b "_"') DO (
FOR /f "tokens=2delims=_." %%y IN ("%%e") DO ECHO REN "%%e" "_%%y%%~xe"
)
POPD
GOTO :EOF
For lack of examples, here's a start.
Always verify against a test directory before applying to real data.
Process the list of filenames that match *_*; find those names that do not start _, pick the second string between the delimiters _ and . and rename using that string (in %%y), prefixed by _ and appended with the original extension.
The ren command is simply echoed to the screen for verification. When happy, remove the echo before the ren to actually execute the rename.
i have loads of files which i want to organize differently. The batch script should create folders with the substring on the left side of the date in the filename.
Files are now named like this:
This_is_my_file_21.01.29_22-00_abc_115.avi
This_is_my_file_20.09.29_21-10_abc_15.avi
This_is_another_file_21.01.29_22-00_abc_55.avi
Pattern:
<Name with unknown number of underscores>_<YY.MM.DD>_<hh-mm>_<string with unknown length>_<number n from 1-999>.avi
Folders should be named like this:
This_is_my_file <- two files will go into this directory
This_is_another_file <- only one file.
The Problem is, how do I get the correct substring for my folder name?
This is what I have so far:
#echo off
setlocal
set "basename=."
for /F "tokens=1* delims=." %%a in ('dir *.avi /B /A-D ^| sort /R') do (
set "filename=%%a"
setlocal EnableDelayedExpansion
for /F "delims=" %%c in ("!basename!") do if "!filename:%%c=!" equ "!filename!" (
set "basename=!filename!"
md "!basename:~0,-23!"
)
move "!filename!.%%b" "!basename:~0,-23!"
for /F "delims=" %%c in ("!basename!") do (
endlocal
set "basename=%%c
)
)
#ECHO OFF
SETLOCAL
rem The following settings for the source directory, destination directory, target directory,
rem batch directory, filenames, output filename and temporary filename [if shown] are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files\t w o"
FOR /f "delims=" %%b IN ('dir /b /a-d "%sourcedir%\*.avi" ' ) DO (
SETLOCAL ENABLEDELAYEDEXPANSION
CALL :countus "%%b"
IF DEFINED subdir (
MD "!subdir!" 2>NUL
ECHO MOVE "%sourcedir%\%%b" "%sourcedir%\!subdir!\"
) ELSE (
ECHO Failed pattern check %%b
)
ENDLOCAL
)
GOTO :EOF
:: count number of underscores before pattern YY.MM.DD_hh-mm
:countus
SET /a ucount=0
:countusloop
SET /a ucount+=1
SET /a scount=ucount+1
FOR /f "tokens=%ucount%,%scount%delims=_" %%q IN ("%~1") DO SET "str1=%%q"&SET "str2=%%r"
IF NOT DEFINED str2 SET "subdir="&GOTO :EOF
:: is %str1%.%str2:-=.%. of form np.np.np.np.np where np is a number-pair?
SET "candidate=%str1%.%str2:-=.%."
FOR /L %%c IN (10,1,99) DO IF DEFINED candidate SET "candidate=!candidate:%%c.=!"&IF NOT DEFINED candidate GOTO success
FOR /L %%c IN (0,1,9) DO IF DEFINED candidate SET "candidate=!candidate:0%%c.=!"&IF NOT DEFINED candidate GOTO success
GOTO countusloop
:success
SET "subdir=%~1"
FOR /f "delims=:" %%e IN ("!subdir:_%str1%_%str2%=:!") DO SET "subdir=%%e"
GOTO :eof
The "move" command is merely echoed for verification. Remove the echo from echo move to actually move the files.
This possible solution uses the fact that your filenames have a known number of underscores if you work backwards. All I do is replace those underscores with backslashes, which obviously cannot already be contained in the filename. I can then use the relative paths to step up the filename, as if it were a directory tree, until all I have left is the part ahead of the date sequence, which I then replace the backslashes with underscores again. I use the result of that with robocopy, which has a move option, and will create the destination directory automatically, if it does not already exist. At the outset, I perform the directory search, in the same directory as the batch-file, using where.exe, (you can change that, on line three, from "%~dp0." to ".", if you want to use the current directory instead, or "any other path" as necessary). where.exe not only treats the ? wildcard as exactly one character, (unlike the dir command which is zero or one), but also ignores 8.3 naming. It therefore treats the .avi extension exactly as written, (and not 'beginning with' .avi, which dir, or a standard for loop, would).
Anyhow, feel free to give it a try:
#Echo Off & SetLocal EnableExtensions DisableDelayedExpansion
Set "}=" & For /F Delims^= %%G In ('(Set PATHEXT^=^) ^& %__AppDir__%where.exe
"%~dp0.":"?*_??.??.??_??-??_?*.avi" 2^> NUL') Do (Set "}=%%~nG"
SetLocal EnableDelayedExpansion & For %%H In ("\!}:_=\!") Do (
EndLocal & For %%I In ("%%~pH..\..") Do (Set "}=%%~pI"
SetLocal EnableDelayedExpansion & Set "}=!}:~1,-1!"
For %%J In ("!}:\=_!") Do (EndLocal & %__AppDir__%robocopy.exe ^
"%%~dpG." "%%~dpG%%~J" "%%~nxG" /Mov 1> NUL))))
If you want even further robustness, and do not wish to use a more suitable scripting technology, the following, extremely complex looking, version, is the same code, except that it uses findstr to validate the date and time sequence. It filters those avi files containing the following pattern, _yy.MM.dd_hh-mm_ in the avi filenames, using all dates from the beginning of 1970 up until the end of 2021:
#Echo Off & SetLocal EnableExtensions DisableDelayedExpansion
Set "}=" & For /F Delims^= %%G In ('(Set PATHEXT^=^) ^& %__AppDir__%where.exe
"%~dp0.":"?*_??.??.??_??-??_?*.avi" 2^> NUL ^| %__AppDir__%findstr.exe
/RC:"_[789][0123456789].0[123456789].0[123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[789][0123456789].0[123456789].0[123456789]_2[0123]-[012345][0123456789]_"
/C:"_[789][0123456789].0[123456789].[12][0123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[789][0123456789].0[123456789].[12][0123456789]_2[0123]-[012345][0123456789]_"
/C:"_[789][0123456789].0[123456789].3[01]_[01][0123456789]-[012345][0123456789]_"
/C:"_[789][0123456789].0[123456789].3[01]_2[0123]-[012345][0123456789]_"
/C:"_[789][0123456789].1[012].0[123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[789][0123456789].1[012].0[123456789]_2[0123]-[012345][0123456789]_"
/C:"_[789][0123456789].1[012].[12][0123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[789][0123456789].1[012].[12][0123456789]_2[0123]-[012345][0123456789]_"
/C:"_[789][0123456789].1[012].3[01]_[01][0123456789]-[012345][0123456789]_"
/C:"_[789][0123456789].1[012].3[01]_2[0123]-[012345][0123456789]_"
/C:"_[01][0123456789].0[123456789].0[123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[01][0123456789].0[123456789].0[123456789]_2[0123]-[012345][0123456789]_"
/C:"_[01][0123456789].0[123456789].[12][0123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[01][0123456789].0[123456789].[12][0123456789]_2[0123]-[012345][0123456789]_"
/C:"_[01][0123456789].0[123456789].3[01]_[01][0123456789]-[012345][0123456789]_"
/C:"_[01][0123456789].0[123456789].3[01]_2[0123]-[012345][0123456789]_"
/C:"_[01][0123456789].1[012].0[123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[01][0123456789].1[012].0[123456789]_2[0123]-[012345][0123456789]_"
/C:"_[01][0123456789].1[012].[12][0123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_[01][0123456789].1[012].[12][0123456789]_2[0123]-[012345][0123456789]_"
/C:"_[01][0123456789].1[012].3[01]_[01][0123456789]-[012345][0123456789]_"
/C:"_[01][0123456789].1[012].3[01]_2[0123]-[012345][0123456789]_"
/C:"_2[01].0[123456789].0[123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_2[01].0[123456789].0[123456789]_2[0123]-[012345][0123456789]_"
/C:"_2[01].0[123456789].[12][0123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_2[01].0[123456789].[12][0123456789]_2[0123]-[012345][0123456789]_"
/C:"_2[01].0[123456789].3[01]_[01][0123456789]-[012345][0123456789]_"
/C:"_2[01].0[123456789].3[01]_2[0123]-[012345][0123456789]_"
/C:"_2[01].1[012].0[123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_2[01].1[012].0[123456789]_2[0123]-[012345][0123456789]_"
/C:"_2[01].1[012].[12][0123456789]_[01][0123456789]-[012345][0123456789]_"
/C:"_2[01].1[012].[12][0123456789]_2[0123]-[012345][0123456789]_"
/C:"_2[01].1[012].3[01]_[01][0123456789]-[012345][0123456789]_"
/C:"_2[01].1[012].3[01]_2[0123]-[012345][0123456789]_"') Do (Set "}=%%~nG"
SetLocal EnableDelayedExpansion & For %%H In ("\!}:_=\!") Do (
EndLocal & For %%I In ("%%~pH..\..") Do (Set "}=%%~pI"
SetLocal EnableDelayedExpansion & Set "}=!}:~1,-1!"
For %%J In ("!}:\=_!") Do (EndLocal & %__AppDir__%robocopy.exe ^
"%%~dpG." "%%~dpG%%~J" "%%~nxG" /Mov 1> NUL))))
I have folder with files named:
-backup- powerpoint1.ppt
-backup- powerpoint2.ppt
-backup- powerpoint3.ppt
I need to rename those files in the same folder to:
powerpoint1.ppt
powerpoint2.ppt
powerpoint3.ppt
I need a batch script to accomplish that.
I have searched online and came up with this so far but the values are resolving properly:
#echo off
setlocal EnableDelayedExpansion
set a=1
for /f "delims=" %%i in ('dir /b *.pptx') do (
set "dt=%%i"
echo.!dt!
set sh=!dt!
echo.!sh!
set "str=%sh:~12,4%"
echo "%%i" "%str%"
set /a a+=1
)
You code does not work as expected, because you missed applying delayed expansion for the interim variables sh and str. Also the extracted string portion !sh:~12,4! is not correct, it should read !sh:~9! in order to remove the -backup- prefix. This is the corrected code:
#echo off
setlocal EnableDelayedExpansion
set a=1
for /f "delims=" %%i in ('dir /b *.pptx') do (
set "dt=%%i"
echo/!dt!
set sh=!dt!
echo/!sh!
set "str=!sh:~9!"
ECHO ren "%%i" "!str!"
set /a a+=1
)
Actually I would not extract certain character positions, but I would remove the constant prefix -backup- by sub-string replacement. And you do not need the interim variables sh and str, neither do you need the counter a. So I would do it like this:
#echo off
setlocal EnableDelayedExpansion
for /f "delims=" %%i in ('dir /b *.pptx') do (
set "dt=%%i"
set "dt=!dt:*-backup- =!"
ECHO ren "%%i" "!dt!"
)
endlocal
After having verified the correct output, remove the upper-case ECHO command from the code to actually rename files.
If the unwanted parts in your file names are space separated a simple:
#Echo off
For /F "delims=" %%A in ('Dir /B/A-D "-backup- powerpoint*"'
) Do For /f "tokens=2" %%B in ("%%A") Do Echo Ren "%%A" "%%B"
Should do (independent of the extension).
Ren "-backup- powerpoint1.ppt" "powerpoint1.ppt"
Ren "-backup- powerpoint2.ppt" "powerpoint2.ppt"
Ren "-backup- powerpoint3.ppt" "powerpoint3.ppt"
I try to improve an overview of my search and find memories for batch files in Windows XP command prompt environment.
In order to my previous sentence I am not happy with my search possibilities and have to post a question.
I try to compare the names of some text files and have written words in a text file that are by reading the same. With such a start environment I wrote following batch script to get an echo output.
The aim is
#echo off
setlocal enabledelayedexpansion
for /f "delims=" %%b in ('dir "C:\A Folder"') do set var=%%~nb & echo !var!
rem The output is the name of the files without extension. Now my question:
rem Is it possible to compare the above file names with some input
rem from a text file, for example like:
for /f "delims=" %%b in ('dir "C:\A Folder"') do set var=%%~nb & for /f %%a in (Textfile.txt) do (if !var!==%%a echo good else echo search)
rem That returns no output. I would like to know if there are possibilities
rem to do that? And if it is possible, how to revise this batch file?
endlocal disabledelayedexpansion
pause
Have a nice day, wishes
Stefan
This should work with Latin characters - some foreign characters may not work:
#echo off
for /f "delims=" %%b in ('dir /b /a-d "C:\A Folder\*.*" ') do find /i "%%~nb" < "textfile.txt" >nul && (echo "%%~nb" found) || (echo "%%~nb" not found)
pause
proper formatting you code increases readabilty:
for /f "delims=" %%b in ('dir /b /a-d "C:\A Folder"') do (
for /f %%a in (textfile.txt) do (
if "%%~nb"=="%%a" ( echo good ) else ( echo search )
)
)
I added a /b to the dircommand (show name only, no date/time/attributes) and a /a-d to exclude directorynames.
You don't need to use a variable (!var!) here (but you can, it works fine).
I have and will have files which are named "x_1.txt x_2.txt x_3.txt, ..." my other program where I input these files cannot recognize the order so it sorts like this "x_1.txt , x_101.txt , x_2.txt"). a solution is to rename the files to x00001.txt , x00002.txt , ....
I have so far wrote the .bat file below, but two problems I have which , I'd be very glad if you help me solve them :
1- how can I remove the 'number'.txt from string x_'number'.txt
2- (solved) how can I use the variable of this string to rename the file name ( the rename part of this file is not working!)
cls
setlocal enabledelayedexpansion
set /A count=100000
for %%f in (*.txt) do (
set /a count+=1
set str=!count:~1!
echo !str!
echo %%f
set filename=%%f
set filename=!filename:~0,5! /Comment: here I want to just keep the x_ part which I don't know how"
echo !filename!
set str3=!filname!!str!
echo !str3!
/// ren %%f !str3!.txt /Comment: Here I cannot use the variable str3,
call:renamer %%f !str3!
)
:renamer
ren %1 %2.txt
Thanks in advance
If the following conditions are true:
You want to rename all of your .txt files in the current folder
All of the .txt files have exactly one _ in the name, immediately before the number
None of your file names contain !
Then the following will work
#echo off
setlocal enableDelayedExpansion
for %%F in (*.txt) do for /f "tokens=1,2 delims=_." %%A in ("%%F") do (
set num=0000%%B
ren "%%F" "%%A!num:~-5!.txt"
)
But to eliminate the conditions requires much more complicated code.
Here is one robust solution that should properly rename all files that meet the template.
It allows for multiple _ in the name.
It only renames files with a name that ends with _NNN.txt where NNN is a number
It properly handles ! in the file name.
Note that it will not properly handle numbers that exceeds 99999. It is simple to expand the degree of 0 padding.
#echo off
setlocal disableDelayedExpansion
pushd .
subst #: .
#:
for /f "eol=: delims=" %%F in ('dir /b /a-d *.txt^|findstr /er "_[0-9]*.txt"') do (
set "name=%%~nF"
setlocal enableDelayedExpansion
for /f "eol=: delims=" %%A in ("!name:_=\x!") do (
endlocal
set "file=%%F"
set "name=%%~pA"
set "num=%%~nA"
setlocal enableDelayedExpansion
set "num=0000!num:~1!"
set "name=!name:~1,-1!"
ren "!file!" "!name:\x=_!!num:~-5!.txt"
endlocal
)
)
popd
subst /d #: