this is my first Q on here, please forgive my ignorance in case I miss on best practices. I've reviewed prior requests to similar tasks, but couldn't apply their solutions to the situation described below.
This is about a CMD batch script to rename certain files only in a DIR and its SUBDIRs. All files share the same pattern:
FILENAME 0000.png
where 0000 is an arbitrary four digit number. Thanks to prior solutions here, I do have a working code for one DIR, alas, adding /r didn't make it recursive.
Below is a code snippet from my current CMD .bat (Win10 x64), removing /r works fine when renaming files in just one DIR only:
:dir_files_rename
SETLOCAL
SET "Path=G:\to\dir"
SETLOCAL enabledelayedexpansion
for /r %%f in ("%Path%\*.png") do if %%f neq %~nx0 (
set "filename=%%~nf"
echo %filename%
ren "%%f" "!filename:~0,-5!%%~xf"
)
ENDLOCAL enabledelayedexpansion
goto start
I don't have a method to identify and pass on exclusively files matching above pattern, because I can't come up such a method (doh!). Not elegant at all, because my code affects all files, but at least that's a start.
Cheers, BF
Related
I've looked around, and there are a lot of posts very similar to this but I can't seem to find an answer that will work for what I need.
I have a big list of files with different extensions that I want to rename to numbers. For example
SomeFileName1.jpg
SomeFileName2.gif
SomeFileName3.mkv
changed to:
1.jpg
2.gif
3.mkv
I want to keep the extensions the same. Only the name should change to 1,2,3 etc.
A while ago I found some code that renamed all the files (don't have the code anymore), but it renamed them in the wrong order. "SomeFileName3.mkv" became "1.mkv" instead of "3.mkv" for example. I'm not sure if I need to sort them first somehow? I'm not very good at this kind of thing so I could really use some help. Thanks
use a for loop to process all files. Use dir to sort the files to your needs. Use a counter. Use delayed expansion to make the counter work.
#echo off
setlocal enabledelayedexpansion
set count=0
for /f "delims=" %%a in ('dir /b /on /a-d') do (
set /a count +=1
ECHO ren "%%a" "!count!%%~xa"
)
for more information read for /?, dir /? and set /?
If the output satisfies you, remove the ECHO to arm the ren command.
I have hundreds of csv files . csv files are stored in folders and sub folders . I want to search fifty csv file whose file names have been determined , for example 1.csv , 2.csv , 3.csv , ... , 50.csv . very troublesome if I searched one by one using the Windows search tool . I would like if the files are found , save in the folder named FOUND . please help to overcome this problem by using the batch programming / bat ? thank you very much
There's a number of approaches one can take, depending on how much automation you require... To help you get started, you may want to look at this it helped me (and indeed continues to do so) when I started learning batch. Furthermore I will provide one possible template for achieving your objective, as I have interpreted it. Perhaps it is not the most elegant or efficient method, but it introduces a number of batch commands that you may or may not have encountered, which in turn may help you develop your own method.
#echo off
setlocal enabledelayedexpansion
echo Please enter a drive letter:
set /p "drive=>"
echo Please enter a search string:
set /p "searchstring=>"
echo %searchstring%>search.txt
set /p search=<search.txt
set /a suffix=0
echo.>>search.txt
:LOOP
for /f "tokens=*" %%i in ("search.txt") do (
set /a suffix=suffix+1
set seq=%search% !suffix!
echo !seq!>>search.txt
)
if !suffix! leq 49 goto LOOP
for /f "tokens=*" %%i in (search.txt) do (
for /f "tokens=*" %%j in ('dir /b /s /a-d %drive%:\"%%i.csv" 2^>nul') do (
if not exist "%~dp0\found" md "%~dp0\found"
move /y "%%j" "%~dp0\found\%%~nxj"
)
)
pause
This is not intended as a definitive solution, though you may find it answers your original query/request. All the best.
Here's another working solution for you..
#ECHO OFF
SETLOCAL EnableDelayedExpansion
REM First Set your directories input and output
SET InputDir=C:\Directory to your CSV files\
SET OutputDir=C:\Directory to your CSV files\FOUND
REM check if the FOUND directory exist, if not, then create it.
IF NOT EXIST OutputDir (
mkdir %OutputDir%
)
REM Grab a scan of the input directory and save it to a temporary file list.
Dir /a /b %InputDir%>"%OutputDir%\Found.txt"
REM Set the files you would like to find.
SET "File1=1.csv"
SET "File2=2.csv"
SET "File3=50.csv"
REM The loop, to process the matching file(s).
FOR %%A IN (%File1%,%File2%,%File3%) DO (
FOR /F "usebackq" %%B IN ("%OutputDir%\Found.txt") DO (
IF %%A==%%B (
copy "%InputDir%\%%A" "%OutputDir%\%%A"
)
)
)
REM Clean up the temp file list.
DEL "%OutputDir%\Found.txt"
Make note, I didn't add quotes to the Input and Output variables, but instead added quotes to the copy portion of the code to compensate for white spaces in your directory path. I tried to keep it simple, so you could follow the logic of how it processed what you are looking for, you can now modify this to your liking.. Have fun. Cheers!
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.
After asking this question on StackOverflow, I've written a .BAT-code that loops through all folders on a shared network drive, lists all files, then outputs HTML.
#echo off
setlocal enabledelayedexpansion
pushd %~dp0
(
echo ^<a href="javascript:toggleAll()" class='toggleAll' style="color:#f57832;" ^>Alles openen^</a^>
for /d /r %%a in (*) do (
pushd "%%a"
set "folder=%%a"
echo ^<h1 onClick="showHide($(this))" class="belangrijkeheader"^>!folder:~25!^</h1^>^<ul class='belangrijkelijst'^>
for /r %%b in (*) do (
set "filename=%%~nb"
set "filename=!filename: =%%20!"
echo ^<li^>^<a href="http://someurl.com:8081/somefolder/!folder:~25!/!filename!%%~xb"^>%%~nb^</a^>^</li^>
)
popd
echo ^</ul^>
)
)>"file.html"
start file.html
pause
It works pretty well, with the exception of subfolders. Each subfolder creates two entries. So, if we had a folder folder1 with two subfolders, subfolder1 and subfolder2 and both had a file, three things would be in the output
Folder1
fileinfolder1.jpg
fileinfolder2.jpg
Folder1/subfolder1
fileinfolder1.jpg
Folder1/subfolder2
fileinfolder2.jpg
I don't want the first entry, since the links are broken, and it doesn't show in what subfolder it is. However, I don't have a clue what to edit in my .bat file to make sure only the second two are shown.
Any assistance would be greatly appreciated.
Your problem is your inner loop is recursively listing all files within the current folder (including subfolders).
All you need to do is remove the /R option.
incorrect
for /r %%b in (*) do (
correct
for %%b in (*) do (
Note - You have additional potential problems.
File names containing ! will fail because delayed expansion will corrupt the FOR variable expansion.
I think there are a number of url encoding issues that you have not addressed, since file names can contain + and %. There may be other issues.
I'm trying to get only one directory name out of a known path while searching for certain file types. In the example below I am searching for mp4 video files then I want to convert them and move them into a subdirectory of the same name in a different parent directory. The path is known up until the file's direct parent directory, so I was trying to remove the known part of the path. This is giving me a lot of trouble though. In the example below, the variable newDir is empty after the set command and it shows only an input of ~13 with #echo on. Can anyone tell me what I'm doing wrong?
Example:
setlocal enabledelayedexpansion
FOR /R %%X in ("*.mp4") DO (
set currDir="%%~pX" &REM "\test1\test2\dir1"
set newDir=%currDir:~13% &REM dir1
mkdir "C:\new\%newDir%" &REM suppose to be "C:\new\dir1", mine is just "C:\new\"
REM convert mp4 here
cp %%X "C:\new\%newDir%" &REM copies the file
)
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR /R "%sourcedir%" %%a IN (*.mp4) DO (
FOR %%m IN ("%%~dpa.") DO ECHO(XCOPY "%%a" "c:\new\%%~nm\"
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
The required XCOPY commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(XCOPY to XCOPY to actually copy the files.
I note that you're using a very cygwinnish cp in place of copy. Be careful of nameclashes. I changed the command to xcopy in order that the destination directory can be automatically generated if required. Note that you haven't said what you want to do if the destination file already exists.
Here's a trial run on my test directory:
XCOPY "U:\sourcedir\misc\90s\ACDC - Back in Black.mp4" "c:\new\90s\"
XCOPY "U:\sourcedir\misc\90s\extended\Kelly Rowland - Wor! (Freemasons Arabic Mix).mp4" "c:\new\extended\"
XCOPY "U:\sourcedir\misc\90s\extended\Kelly Rowland - Work (Freemasons Arabic Mix).mp4" "c:\new\extended\"
XCOPY "U:\sourcedir\one\dummyfile1.mp4" "c:\new\one\"
XCOPY "U:\sourcedir\t w o\dum myfile2.mp4" "c:\new\t w o\"
XCOPY "U:\sourcedir\t w o\dum ile2.mp4" "c:\new\t w o\"
With enabledelayedexpansion in for loop, you should use !newDir! instead of %newDir%, and also !currDir:~13! instead of %currDir:~13% to make delayed expansion happen.
[update] There're also small errors. You should be careful about the spaces and quotes when you set to variables. They are actual part of the string to be set. And you have mkdir the same directory several times, and also it's better to user copy or xcopy instead of 'cp' which should be from "Cygwin" or "MinGW32" or something. xcopy will automatically create folders for you if not exist.
To make your codes work, please see below. And just a suggestion that you'd better learn more basic knowledge about bat before starting programming.
#echo off & setlocal enabledelayedexpansion
FOR /R %%X in ("*.mp4") DO (
set currDir=%%~pX
set newDir=!currDir:~13!
REM mkdir "C:\new\!newDir!"
REM convert mp4 here
xcopy "%%X" "C:\new\!newDir!"
)