Copy, rename and move all files in directory - batch-file

I have many pdf files I need to Copy, Rename and Move.
Copy and move works – I just can’t figure out how the rename part it’s done.
The files look like this:
2021-05-05_10-10-12-609_Testperson_Nancy_2512489996_19490816_OD_20210429112706.pdf
2021-06-05_11-11-12-135_Testperson_with_many _Names_0708681234_19490817_OD_20210429112715.pdf
and I need them to be renamed to:
251248-9996_19490816_OD_20210429112706.pdf
070868-1234_19490817_OD_20210429112715.pdf
So need to substring from the fourth _ from the right (without the first _) with a - between [6] and [7].
This is what I got so far:
SET input=c:\temp\rename\input
SET backup=c:\temp\rename\backup
SET output=c:\temp\rename\output
if not exist "%backup%" mkdir "%backup%"
for /f "tokens=*" %%F IN ('DIR /S /B "%input%\*.pdf"') DO (
xcopy /-y "%%F" "%backup%" & move "%%F" "%output%"
)
c:\temp\rename\input (for original files)
c:\temp\rename\backup (backup dir for orginal files)
c:\temp\rename\output (renamed files)
This must be run as a scheduled batch file job on Windows Server (I know how to run the job)

Give this a go. I would suggest you first make a backup of your files before running this in on your production files:
#echo off & setlocal enabledelayedexpansion
set "input=c:\temp\rename\input"
set "backup=c:\temp\rename\backup"
set "output=c:\temp\rename\output"
mkdir "%backup%">nul 2>&1
for /f "delims=" %%i in ('dir /b /s /a-d "%input%\*.pdf"') do (
set "cnt=-4"
set "_tmp=%%~i"
set "_tmp=!_tmp: =-!
set "_strip=!_tmp:_= !"
for %%c in (!_strip!) do (
set /a cnt+=1
)
if !cnt! gtr 1 if defined _tmp call :parser !cnt! "%%i"
)
goto :eof
:parser
for /f "tokens=%~1,* delims=_" %%a in ("%~2") do set "fin=%%~b"
echo xcopy /-y "%~2" "%backup%"
echo move "%~2" "%output%\%fin:~0,6%-%fin:~6%"
Some things to note. This does not yet do the actual copy or move, it will just echo the results, as a safety measure. So once you see it does what it should, then you can remove echo from the last two lines.
Lastly this is assuming the file format as you gave it, but it does cater for whitespace as well as double _ but it will go south if you have another _ separated section which does not form part of the standard format.
Demo
Given the 4 examples you gave in your question and comment (with the exception of the C:\tmp\Input in my example as I use a different directory to test):

You could probably do this easier using PowerShell, but to remain on topic, here's a batch-file which gets some assistance from powershell:
#Echo Off
SetLocal EnableExtensions
Set "input=C:\temp\rename\input"
Set "backup=C:\temp\rename\backup"
Set "output=C:\temp\rename\output"
For /F "Tokens=1-2 Delims=|" %%G In (
'%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile
"Get-ChildItem -LiteralPath '%input%' -Filter '*_*_*_*_*.pdf' -File | "
"ForEach-Object { $_.FullName + '|' + "
"(($_.Name).Split('_')[-4]).Insert(6,'-') + '_' + "
"(($_.Name).Split('_')[-3..-1] -Join('_')) }"') Do (
Echo=%SystemRoot%\System32\xcopy.exe "%%G" "%backup%\" && (
Echo=Move /Y "%%G" "%output%\%%H"))
Pause
Currently the script will just show you the commands it will run, if you're happy with the output, then delete Echo= from lines 12 and 13 and optionally the last line. As a side note, I used a trailing backward slash for the xcopy destination, this will cause %backup% to be created, if it does not already exist.

Related

How do I replace spaces and symbols in all files and FOLDERS with a batch file

I'm very close I think. I have a folder where-in I'm trying to rename all the sub folders and files such that caps are stripped, symbols replaced with applicable words, and spaces changed to hyphens in both the files AND their parent sub-folders.
Here's the batch file I have so far:
cd d:\scripts\testing\
for /r %%D in (.) do #for /f "eol=: delims=" %%F in ('dir /l/b "%%D"') do #ren "%%D\%%F" "%%F"
SET location=d:\scripts\testing\
for /R %location% %%A in (*.*) do call :replspace "%%A"
for /R %location% %%A in (*.*) do call :repland "%%A"
goto :eof
:replspace
set "_fn=%~nx1"
ren %1 "%_fn: =-%"
:repland
set "_fn=%~nx1"
ren %1 "%_fn:&=and%"
As you might be able to see, first it goes through and renames everything (files and folders) in d:\scripts\testing\ to lower-case. Next it renames all files in that same directory to replace spaces with hyphens and "&" with the word "and". This all works... except I need to do the same symbol and space changes to the folders and I'm not finding any real info on how to do that.
Anyone have any suggestions?
BTW, this runs on server 2012 r2, however for interoperability issues, the scripts have to be old fashioned batch scripts.
You can perform the entire replacement task with one for loop., by using dir /s to recursively search the directory.
#echo off
setlocal enabledelayedexpansion
pushd "d:\scripts\testing\" || goto :EOF
for /f "delims=" %%i in ('dir /b /l /s') do (
set "item=%%~i"
set "item=!item:%%~dpi=!"
set "item=!item: =-!"
ren "%%~fi" "!item:&=and!"
)
popd
I did not set the & replacement as a variable seeing as there are only two replacements done, so simply using the substitution on the last item makes sense without the need to set again. If you have more replacements to add, add them before the ren line:
Note that this example will merely echo the results for testing purpose. Only remove echo once you're convinced the results are as expected.
Then, take note of || goto :EOF in the pushd statement. This is critical for good reason. Should it fail to cd or pushd, generally the script will continue with the rename, from the working directory it was started in, or a previous cd pushd etc. In this case, if it fails to find the directory, or it does not have permission, it will skip the remainder of the script entirely.
Final Note. Should your files or folders contain ! this will need to change. You can then simply revert to moving the set and ren to a label, then call the label as delayedexpansion will cause the ! to be lost.
While Gerhard's script is clean and should work, it trips on itself under certain circumstances like mine. I wound up using this script:
rem #### Step 1: move to working directory ####
cd "d:\scripts\testing\"
rem #### Step 2: change case on everything ####
for /r %%D in (.) do #for /f "eol=: delims=" %%F in ('dir /l/b "%%D"') do #ren "%%D\%%F" "%%F"
rem #### Step 3: set location ####
SET location=d:\scripts\testing\
for /R %location% %%A in (*.*) do call :replspace "%%A"
for /R %location% %%A in (*.*) do call :repland "%%A"
rem #### Step 4: replace spaces/symbols on directories ####
setlocal enabledelayedexpansion
pushd "D:\scripts\testing\" || goto :EOF
for /f "delims=" %%i in ('dir /l /b /s /ad') do (
set "item=%%~i"
set "item=!item: =-!"
move "%%~fi" "!item:&=and!"
)
popd
rem #### variables ####
:replspace
set "_fn=%~nx1"
ren %1 "%_fn: =-%"
:repland
set "_fn=%~nx1"
ren %1 "%_fn:&=and%"
Its a combination of my own script and a slight modification of Gerhard's script. Bassically I ended up stepping through the modifications.
change everything to lower case.
replace spaces and symbols in the file names.
replace spaces and symbols in the directory names.
I know it's repetitive and I'd like to do it with less lines, but it works.

net use - Causing Echo Redirect to Fail

I have a script that successfully scans a specified directory for a list of files, copies the files to a destination folder and generates a log of all files not found in the source. I had to alter this script to include net use in order to map a network drive. Since doing so the script no longer generates the error log as it did before.
I'm very new to this and can't find any information on why this may be happening. Can somebody please help?
#echo off
pause
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
net use U: \\abc\def
SET "src="U:\Source Folder""
SET "dst=C:\Destination Folder"
SET "file_list=C:\files.txt"
SET "out=.\errors.log"
echo > %out%
FOR /F "usebackq eol=| delims=" %%f IN ("%file_list%") DO (
rem just searching to find out existense of file
WHERE /Q /R %src% "%%f"
IF "!ERRORLEVEL!" == "0" (
FOR /F "usebackq eol=| delims=" %%s IN (`WHERE /R %src% "%%f"`) DO (
echo "%%s => %dst%\%%f" >> %out%
#copy /y "%%s" "%dst%\%%f"
)
) ELSE (
echo %%f >> %out%
)
)
Replace echo %%f >> %out% with set /p out=%%f
[Edit]
Sorry I misunderstood your question.
Is it because you have two quotation marks in all of the drive path set?
As in replace
SET "src="U:\Source Folder""
With
SET src="U:\Source Folder"

copy & rename files to other folder

I have some of log files formatted like this "name.log"
I would like to copy those from one folder to another folder like
xcopy /y "C:\Folder1" "D:\Folder2"
And i need to rename file with created date of original file (no copy file) so that the text file in Folder2 would be like "name yyyymmddhhmm.log" if some file has the same name (date of creation) it will be overwritten.
The code:
set Source=C:\Users\user1\Desktop\Folder1
set Dest=D:\Folder2
if not exist %Dest% md %Dest%
for /F %%a in ('dir /b "%Source%\*.txt"') do call :Sub %%a
goto :eof
:Sub
set "filename=%1"
for /F %%s in ("%Source%\%1") do if %%~zs==0 goto :eof
set "datepart="
FOR /F "tokens=1-5 delims=/-: " %%a IN ('dir /tc "%filename%" ^| findstr "%filename%"') DO (
IF "%%c" neq "" SET "datepart=%%c%%a%%b%%d%%e"
)
FOR /F %%a IN ("%filename%") DO (
set "NewName=%%~na %datepart%%%~xa"
)
xcopy /y "%Source%\%filename%" "%Dest%\%NewName%*"
GOTO :EOF
The problem is that If I don't put the .bat in the same folder that origin files (Folder1),the files aren't change name. For example, if it is out, the files change name with old name and one white space.
The command windows tell me that it doesn't find the file when it get the creation date.
If I put the script into folder1 it works well.
On the other hand, if I execute the script with "Task Scheduler" I have the same problem. The files are copied but without date of creation.
What do I need to solve this problem?
#ECHO OFF
SETLOCAL
set Source=C:\Users\user1\Desktop\Folder1
set Dest=D:\Folder2
set "Source=u:\sourcedir\t w o"
set "Dest=u:\destdir"
if not exist "%Dest%" md "%Dest%"
for /F "delims=" %%k in ('dir /b "%Source%\*.log"') do call :Sub "%%k"
goto :eof
:Sub
SET "newname=%~1"
for /F "delims=" %%s in ("%Source%\%~1") do (if %%~zs==0 goto :eof
FOR /F "tokens=1-5 delims=/-: " %%a IN ('dir /tc "%Source%\%~1" ^| findstr "%~1"') DO (
IF "%%c" neq "" SET "newname=%%~ns %%c%%a%%b%%d%%e%%~xs"
)
)
ECHO(xcopy /y "%Source%\%~1" "%Dest%\%NewName%"
GOTO :EOF
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. Append >nul to suppress report messages (eg. 1 file copied)
This may seem quite a radical change, but actually it really isn't.
First issue is that I overrode your directory settings with directories to suit my system. The syntax SET "var=value" (where value may be empty) is used to ensure that any stray trailing spaces are NOT included in the value assigned. set /a can safely be used "quoteless".
Using quotes in the md command makes the procedure immune to "paths containing separators" - I test using spaces in paths and filenames because that appears to be a popular thing to do.
I changed the directory-scan metavariable from %%a to %%k to avoid confusion with the %%a in the subroutine. Your text says that you are starting with &.log files, but your filemask was *.txt so I changed it to *.log. Quoting the parameter delivered to :Sub means the procedure will receive the entire name of the file if it contains spaces.
Within the subroutine, it would appear that yowant no name-change if the %%c part from the dir/tc scan is empty. %~1 is the supplied filename minus the quotes.
The outer loop in %%s : I added delims= to cater for spaces in filenames and used %~1 in preference to %filename%
Within the %%s block, %%s refers to the file, so you can use %%s and its modified forms like %%~zs to refer to that file's characteristics - which unfortunately do not include create-date (%%~ts contains the last-update date - you may be able to use that in te following line rather than dir and findstr)
Then as #aschipfi suggested, include the source directory in the dir otherwise the dir takes place on the current directory.
FOR /F "tokens=1-5 delims=/-: " %%a IN ("%%~ts") DO (
should work for you if you can use last-update-date in place of create-date.
So - if %%c is not empty, set the new name to (the name part of the file in %%s)+space+the date string+(the extension in %%s)
And then do the xcopy - using the old name unless it was modified.

Rename A Sub-Directory the parent folder name if NOT called "info"

Is it possible to make a batch file that will rename a folder if does not have a specific name?
EG:
Parent Directory
- - - > info
- - - > randomfoldername
I have many folders that follow the above pattern. What I would like to do is make a batch file that will rename "randomfoldername" in this structure. There is always two folders in the Parent Directory, one is always "info" and the other changes for each case. Is there a method within a batch file that I could use to always rename the "randomfoldername" directory? I was thinking something along the lines of,
IF NOT == "info" THEN ren... ect.
Is this possible?
you can first check if folder exist then rename folder
if not exist c:\info ( call random.bat )
random.bat:
dir /A:D /b | findstr.exe /n /R "." > s:\sites\file-count.txt
FOR /F "tokens=1-10 delims=:" %%A IN ('type "s:\sites\file-count.txt"') do
set NUMBER-OF-FILES=%%A
FOR /L %%A IN (1,1,%number-of-files%) DO CALL RENAME.bat %%A
rename.bat
:rename
FOR /F "tokens=1-10 delims=:" %%A IN ('type "s:\sites\file-count.txt" ^|
findstr "%1:"') do ren %%B %RANDOM%%%B
also u can use free tool like Bulk Rename Utility
that app has cli for use in bat file here
also You can use powershell script like
$a = test-path c:\info
if ( $a -eq "True" ) { Write-Host nothing to do } Else { gic -directory path | %{$n="$pwd\$((get-random).tostring())$($_.name)";$_.moveto($N)} }
Next script starts with basic checks on command line parameter passed into.
FOR /F loop against the results of another command (dir) used. Next explanation stolen (see dbenham's original) :
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.
#ECHO OFF >NUL
SETLOCAL enableextensions disabledelayedexpansion
set "ParentDirectory=%*"
if "%ParentDirectory%"=="" goto :usage1
if not exist "%ParentDirectory%\" goto :usage2
if not exist "%ParentDirectory%\info\" goto :usage3
set "SpecificName=Desired Name"
set /A "count=0"
for /F "delims=" %%G in ('dir /B /A:D "%ParentDirectory%\"') do set /A "count+=1"
if %count% neq 2 goto :usage4
for /F "delims=" %%G in ('dir /B /A:D "%ParentDirectory%\"') do (
if /I not "%%~G"=="info" (
if /I not "%%~G"=="%SpecificName%" (
echo renaming "%ParentDirectory%\%%~G" to "%SpecificName%"
rename "%ParentDirectory%\%%~G" "%SpecificName%"
) else (
echo renamed already: "%SpecificName%"
)
)
)
:endlocal
ENDLOCAL
goto :eof
:usage1
echo no paramater
goto :endlocal
:usage2
echo "%ParentDirectory%" folder does not exist
goto :endlocal
:usage3
echo "%ParentDirectory%\info" folder does not exist
goto :endlocal
:usage4
echo "%ParentDirectory%" folder contains %count% subfolders
goto :endlocal
Output:
==>29376745.bat
no paramater
==>29376745.bat x y
"x y" folder does not exist
==>29376745.bat d:\test
"d:\test\info" folder does not exist
==>md "d:\test\info"
==>29376745.bat d:\test
"d:\test" folder contains 6 subfolders
==>29376745.bat d:\test\29376745
renaming "d:\test\29376745\currentName" to "Desired Name"
==>29376745.bat d:\test\29376745
renamed already: "Desired Name"
==>
Required reading (indexes only):
An A-Z Index of the Windows CMD command line
Windows CMD Shell Command Line Syntax

Batch Rename by Replace substring

Hello :) when a friend give you a mp3 file, most often, the title is named that way: "avenged_sevenfold_-_buried_alive.mp3". i want to make a script which permit me to rename every file and folder of current repertoryby replacing "_" by " "(space). this is very long to rename each file manually; my script is here:
#echo off
title Merci qui ?
:debut
echo do you want to rename every files/foldes by replacing "_" by " "? (y/n)
set /p choix=
if %choix%==y (
goto renomage)
if %choix%==n (
goto end)
goto debut
:renomage
set /a x=1 :pointeur de fichier
set /a compteurA=0
set /a compteurB=0
for /f %%a in ('dir /b /a:-d *.*') do set /a compteurA+=1
for /f %%a in ('dir /b /a:d *.*') do set /a compteurB+=1
echo %compteurA% fichiers %compteurB% dossiers
set /a n=compteurA+compteurB
echo number of folder/files batch included %n%
:while1
if %x% GTR %n% goto prochain1
set Strin=???name?ofthe?dossier?number?x?????????????
for /f "tokens=1,* delims=[,]" %%A in ('"%comspec% /u /c echo:%Strin%|more|find /n /v """') do `set /a l=%%A-4`
echo Le nom contient %l% lettres.
:leftspace
set Strin=%Strin:_= %
set str=%Strin:~0,1%
if %str% EQU " "(
set Strin=%Strin:~1,%l%-1%
goto leftspace)
SET /A x +=1
goto while1
:prochain1
echo Success ! (or not)
pause
:end
i just need help for this line:
set Strin=???name?ofthe?dossier?number?x?????????????
otherwise the rest should be ok. if you have some critics or something, go on =)
This solution is reposted from How to Batch Rename Files in Windows: 4 Ways to Rename Multiple Files by Chris Hoffman
PowerShell offers much more flexibility for renaming files in a command-line environment. Using PowerShell, you can pipe the output of one command – known as a “commandlet” in PowerShell terms — to another command, just like you can on Linux and other UNIX-like systems.
First of all, open Powershell ISE and then navigate to the directory (folder) that has the files and folders you'd like to rename by using this command:
cd "C:\your\directory\"
The two important commands you’ll need are Dir, which lists the files in the current directory, and Rename-Item, which renames an item (a file, in this case). Pipe the output of Dir to Rename-Item and you’re in business.
After you launch PowerShell ISE, use the cd command to enter the directory containing your files. You should put the files in their own directory so you don’t accidentally rename other files.
For example, let’s say we don’t want the underscore character in our file names – we’d rather have a space instead.
The following command lists the files in the current directory and pipes the list to Rename-Item. Rename-Item replaces each underscore character with a space.
Dir | Rename-Item –NewName { $_.name –replace "_"," " }
Replace the "_" and "" parts of the command to replace other characters in file names.
Consult Microsoft’s documentation on the Rename-Item commandlet if you want help performing other, more advanced operations.
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR %%f IN (ad a-d ) DO FOR /f "delims=" %%a IN (
'dir /b /s /%%f "%sourcedir%\*" '
) DO CALL :chgnam %%a
GOTO :EOF
:chgnam
SET "name=%*"
SET "newname=%name:_= %"
IF "%newname%" neq "%name%" ECHO REN "%name%" "%newname%"
GOTO :eof
The required REN commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(REN to REN to actually rename the files and directories. Directories are renamed first.
You will need to change sourcedir to point to your required directory. All files and directories in the tree which contain the _ would be renamed - if it's possible to rename them.
[revised and corrected version]
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
PUSHD "%sourcedir%"
FOR %%f IN (ad a-d ) DO FOR /f "delims=" %%a IN (
'dir /b /s /%%f "%sourcedir%\*" '
) DO CALL :chgnam "%%a" "%%~nxa"
POPD
GOTO :EOF
:chgnam
SET "name=%~2"
SET "newname=%name:_-_=-%"
SET "newname=%newname:_= %"
IF "%newname%" neq "%name%" ECHO(REN "%~1" "%newname%"
GOTO :eof
The original version would show incorrect ren syntax (the new-name may not contain a path)
If you want to run on the current directory, simply set the value of sourcedir to a single dot.

Resources