I need to change a file name in a batch script.
Below is a sample I made
SET date = 20210803
SET job = 69187
cd "H:\arbortray foldher\"
for %%i in (*.txt*) do REN %%i randum_%job%-text-%date%%%i
It is not working; does nothing. I want it to change a specific file name from a generic version to one using the globally defined variables that are used through out the script. The file is already being moved from another program that makes the file into this folder. I can not include the variable in the file name at those steps. I want to include the commands as part of a larger script that does other things using the variables. Specifically, in this case I need the commands to rename the file from the generic version to one that includes variables defined earlier in the script. These variables change weekly.
The problems are:
A) Your variable names will have spaces in them.
B) The CD command needs a /d
C) The for in do has a bug which has to be worked around by changing the extension and restoring it later.
#echo off
SET date=20210803
SET job=69187
cd /d "H:\arbortray foldher\"
for %%i in (*.txt) do REN "%%i" "randum_%job%-text-%date%%%~ni.tmp"
ren *.tmp *.txt
echo done
pause
The spaces caused the issue and in the rename command you need double quotes to cater for spaces.
take a look at the cross-platform renamer tool..
your example insecure:
date (isn't good practica)
md itsdir.txt
ren %UNICODECHARS% %insecure?%
answer:
#echo off
chcp 65001 >NUL 2>NUL.
set "v_date=20210803"
set "v_job=69187"
set "v_dir=%cd%"
for /f "tokens=* delims=" %%s in ('dir /b /a-d "%v_dir%" ^| findstr /i /e /c:".txt"') do #ren "%v_dir%\%%s" "randum_%v_job%-text-%v_date%%%s"
forgot about /d and cd ))
maybay you mean "randum_69187-text-20210803-example.txt" in example result?
Related
I am trying to rename every image in a directory to add the date that each file was created, however, I keep either getting "invalid syntax" or "A duplicate file name exists, or the file cannot be found"
I am running Windows 10, and accessing the images off a flash drive (hence the short file path). I tried having all the code in one for-loop, when that didn't work I tried using batch functions, no dice. I did see someone mention on another thread to use delayed expansion, I would be up for using this if someone could give a better explanation than the /? command.
#echo off
REM batch file is placed in top of F drive, same as "images 2017+"
cd "F:\images 2017+"
FOR /R "F:\images 2017+" %%F in (*.jpg) do call :renER "%%~nF" "%%~tF"
goto :eof
:renER
cd "F:\images 2017+"
pause
echo %1
echo %2
rename %1.jpg %1_%2.jpg
pause
goto :eof
:end
For every .jpg file in "images 2017+", the date which that file was created would be stuck onto the end after a space.
thisIsMyFile.jpg made at 5-13-2017, would become thisIsMyFile 5-13-2017.jpg
Current output
EDIT:
I am CDing into the same directory as the images are, then using the passed variables to locate the correct image (The date is one of the passed variables, and shows up in the echo command).
I notice that you only want the date, not the time so you can do that as follows using your existing Call to a label, There is also no need to use FOR /R in this case so I'll use a normal for loop:
#echo off
FOR %%A IN ("F:\images 2017+\*.jpg") DO (
CALL :RenER "%%~fA" %%~tA
)
GOTO :eof
:RenER
PAUSE
ECHO %1
ECHO %2
SET "_tmp=%~2"
SET "_tmp=%tmp:/=-"
REN "%~1" "%~n1_%_tmp%%~x1"
PAUSE
GOTO :eof
Notice how above we are dropping the Time off immediately by not wrapping it in quotes since you don't want that to be part of the file name.
You can also forgo the call to a label entirely without needing delayed expansion by using a second loop, as a matter of preference I think this is quite a bit cleaner!
#echo off
FOR %%A IN ("F:\images 2017+\*.jpg") DO (
FOR /F "Tokens=1-3 Delims=/ " %%a IN ('echo.%%~tA') DO (
PAUSE
ECHO.%%~fA
ECHO.%%~tA
REN "%%~fA" "%%~nA_%%a-%%b-%%c%%~xA"
PAUSE
)
)
this is nice and clean and with a minor edit we can paste it directly into the CMD Prompt which is nicer still This is because we are not using DelayedExpansion, Calling a Label, or using Temp variables so by changing the %%s to %s, we can then Paste this directly into the CMD Line which is often more convenient when doing these sorts of operations:
This Multi-line will do just fine to be pasted into CMD directly:
FOR %%A IN ("F:\images 2017+\*.jpg") DO (
FOR /F "Tokens=1-3 Delims=/ " %a IN ('echo.%~tA') DO #(
PAUSE
ECHO.%~fA
ECHO.%~tA
REN "%~fA" "%~nA_%a-%b-%c%~xA"
PAUSE
)
)
or, as a single line to paste into CMD if you prefer:
FOR %A IN ("F:\images 2017+\*.jpg") DO #( FOR /F "Tokens=1-3 Delims=/ " %a IN ('echo.%~tA') DO #( PAUSE& ECHO.%~fA& ECHO.%~tA& REN "%~fA" "%~nA_%a-%b-%c%~xA"& PAUSE ) )
no need to cd anywhere. ren takes a full path/filename for source - just the destination must be a filename only. So ... do call :renER "%%~fF" "%%~tF" is fine (no need to snip the extension and add it again later). In the subroutine reformat the time to a valid string and reassemble the destination file name:
#echo off
FOR /R "F:\images 2017+" %%F in (*.jpg) do call :renER "%%~fF" "%%~tF"
goto :eof
:renER
pause
echo %1
echo %2
set "string=%~2"
set "string=%string::=-%"
set "string=%string:/=-"
ECHO rename "%~1" "%~n1_%string%%~x1"
pause
goto :eof
:end
NOTE: I disarmed the rename command. Remove the ECHO after troubleshooting, if it works as intended.
#Stephan's answer is probably the best approach. But if you want to change directories ...
The windows shell has a working drive/volume, and on each drive/volume a current working folder. cd changes the working folder on a disk; to change the working folder on a drive (which is not the working drive) and to make that drive the working drive, you need to use cd /d, in this case cd /d "F:\images 2017+".
(A plain cd in this instance changes the working folder on F:\, but if your working folder is on C: -- as I'm guessing is the case -- it will not be changed.)
Assuming command extensions are enabled, you should also be able to use pushd and popd. pushd behaves like cd /d but also saves your previous location; popd returns you to that previous location. (And IIRC pushd will accept UNC paths.)
So at the beginning of your script, pushd "F:\images 2017+", and at the end popd.
I tend to favor pushd/popd over cd because invocations can be nested. So you can do things like
(assume working directory is C:\Users\IoCalisto):
pushd "F:\images 2017+"
(working directory is now F:\images 2017+)
pushd "Z:\images 2015-2016"
(working directory is now Z:\images 2015-2016)
popd
(working directory is now F:\images 2017+)
popd
(working directory is now C:\Users\IoCalisto)
... with this approach, your scripts will have fewer "side effects" and be more modular, or at least modularizable.
I have a folder called TEST. Inside there are 30 files.
Example:
DIM1_UPI_20170102.TXT
DIM2_UPI_20170908.TXT
DIM3_UPI_20180101.TXT
...
I have to rename them by removing the date tag
Exapmple:
DIM1_UPI.TXT
DIM2_UPI.TXT
DIM3_UPI.TXT
Can you please help me writing this in batch file?
Assuming your files are all starting with DIM
#echo off
setlocal enabledelayedexpansion
for /f %%i in ('dir "*.TXT" /b /a-d') do (
set "var=%%~ni"
echo ren !var!%%~xi !var:~0,-9!%%~xi
)
Once you can confirm that it does what you want, and ONLY then, remove the echofrom the last line to actually rename the files.
Important Note. If you have files with similar names, but different date entries, this will not work as you think. as Example:
DIM2_UPI_20170910.TXT
DIM2_UPI_20170908.TXT
The names are the same, but dates differ, making each filename Unique. If you rename them, there can be only 1 DIM2_UPI.TXT So as long as you understand this, you will be fine.
Edit: based on Amazon drive question. Note you need to change the directory portion to how you access amazon drive.
#echo off
setlocal enabledelayedexpansion
for /f %%i in ('dir "DIM*" /b /a-d') do (
set "var=%%~ni"
echo ren !var!%%~xi !var:~0,-16!%%~xi
)
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.
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!"
)
I have a directory with the following structure:
C:\Directory1\
sub1\
sub2\
sub3\
somefilename.txt
someotherfile.txt
Inside each sub*\ there are .dat files that I need to copy to another directory mirroring along the way the directory name where they were found. So if I find C:\Directory1\sub2\file.dat I would copy that into C:\mirror\sub2\file.dat and so on.
I tried several combinations of things similar to
for /R %SRC_DIR% %%f in (*.dat) do copy "%%f" %BACKUP_DIR%\%%~nf%%~xf
(please note this is just an example of code I was playing with, i know it doesn't work)
anyway, after trying to a couple of day I still don't know how to do it. Any chance of help?
Code is appreciated.
thanks!
This works for me:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set SourceDir=c:\source\dir
set TargetDir=d:\target\path
set FileMask=*.cpp
for /r "%SourceDir%" %%F in (%FileMask%) do (
call :ReplacePrefix target_path "%%~F" "%SourceDir%" "%TargetDir%"
call :CopyFile "%%~F" "!target_path!"
)
endlocal
goto :EOF
:CopyFile %1=source_path %2=target_path
mkdir %~dp2
copy %1 %2
goto :EOF
:ReplacePrefix %1=result_var_name %2=string %3=replace_what %4=replace_with
rem a question mark is prepended to ensure matching only at the beginning of the string
set rp_value=?%~2
call :DoIt "set %1=%%rp_value:?%~3=%~4%%"
goto :EOF
:DoIt %1=cmd
%~1
goto :EOF
Keep in mind though that it can break if paths contain unusual characters (such as = and some others which I can't remember now).
Use the following XCOPY command:
xcopy "c:\directory1\*.dat" "c:\mirror\" /s /v /c /y
If you do not want to see the filenames displayed on the screen add '/q' to the list of options.
The '/s' will copy files from subfolders. If the subfolders don't already exist they will be created.
The '/v' forces verification. Not necessary but it's nice to have that peace of mind.
The '/c' forces XCOPY to continue with the rest of the files if it encounters any problems - in other words, your batch file won't halt abruptly with only 'some' of your files copied. XCOPY will copy all that it can.
The '/y' suppresses prompting to overwrite an existing file.