Copy Subdirectories, Keep the Larger File - windows

I'm trying to combine two directories on a Windows 7 machine that have some of the same subfolders (but not all) and some of the same files (but not all). I'd like to copy
For example, I have the following directory structure and want to combine (copy or move) "Dir_A" and "Dir_Z". Where the file exists in the destination directory, I want to compare filesizes and keep the larger of the two files.
Dir A
Dir B
file 1.txt
file 2.txt
file 3.txt
Dir C
file 4.txt
Dir D
file 5.txt
file 6.txt
Dir_Z
Dir Y
file 8.txt
Dir C
file 4.txt
Dir D
file 6.txt
I'm comfortable using a cmd file or powershell. Thank you in advance.
EDIT: Modify to include spaces in the director and file names and add what I have so far.
Here's what I've been able to do so far. It appears to work with the exception of when there are spaces in the directory or filenames.
#echo off
echo :: Combine two folders, Keep the larger of any given files, Delete the other
if "%1"=="" goto :NoParam
if "%2"=="" goto :NoParam
setlocal enabledelayedexpansion
set SOURCE_DIR=%1
set DEST_DIR=%2
for /R "%SOURCE_DIR%" %%S in (*) do (
echo Source: "%%S"
#echo off
for /f "delims=" %%R in ('call MakeRelative.cmd "%%S" "%SOURCE_DIR%"') do (
set FILE_REL="%%R"
set filename=%DEST_DIR%\%%R
For %%D in ("!filename!") do (
Set Name=%%~nxD
if exist %DEST_DIR%\%%R (
echo File Exists
if %%~zD lss %%~zS (
echo Destination %%~zD is smaller than Source %%~zS
call robocopy %%~dpS %%~dpD "!Name!" /MOV
) else del %%S && Echo File is not larger, Deleting %%S
) else call robocopy %%~dpS %%~dpD "!Name!" /MOV
)
)
)
Pause
goto :eof
:NoParam
echo.
echo Syntax: %0 [Source_DIR] [Dest_DIR]
goto :eof
I make use of the MakeRelative.cmd as outlined here: http://www.dostips.com/DtCodeCmdLib.php#MakeRelative
I apologize that this is not elegant.

I'm not much of a PowerShell developer, but this should do the work and is hopefully somewhat more obvious regarding what it's doing than the batch file.
if($args.length -ne 3) {
"usage: PowerShell ThisScriptName.ps1 -command ""SourceDirectory"" ""DestinationDirectory""";
Exit
}
function CopyFileIfSourceIsLarger($SourceFile, $DestinationFile) {
$S = New-Object IO.FileInfo($SourceFile.ToString());
$D = New-Object IO.FileInfo($DestinationFile.ToString());
if ($S.Length -gt $D.Length ) {
"Overwriting smaller file " + $D.FullName;
[IO.File]::Copy($S.FullName, $D.FullName, $true);
}
}
$SourceDir = New-Object IO.DirectoryInfo($args[1]);
$DestinationDir = New-Object IO.DirectoryInfo($args[2]);
$SourceDirectoryPath = $SourceDir.FullName;
$DestinationDirectoryPath = $DestinationDir.FullName;
"Source Path: " + $SourceDirectoryPath;
"Destination Path: " + $DestinationDirectoryPath;
$SourceItems = Get-ChildItem -recurse $SourceDir;
"Synchronizing Directory Structure..."
foreach ($dir in $SourceItems | ? { $_ -is [IO.DirectoryInfo] }) {
$sourceRelative = $dir.fullname.Substring($SourceDirectoryPath.length + 1);
if ([IO.Directory]::Exists([IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative)) -eq $false) {
"Creating folder " + [IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative);
[IO.Directory]::CreateDirectory([IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative)) | out-null;
}
}
"Synchronizing Files..."
foreach ($file in $SourceItems | ? { $_ -is [IO.FileInfo] }) {
$sourceRelative = $file.fullname.Substring($SourceDirectoryPath.length + 1);
if ([IO.File]::Exists([IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative)) -eq $true) {
CopyFileIfSourceIsLarger ([IO.Path]::Combine($SourceDirectoryPath,$sourceRelative).ToString()) ([IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative).ToString());
} else {
"Creating file " + [IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative);
[IO.File]::Copy([IO.Path]::Combine($SourceDirectoryPath,$sourceRelative).ToString(),[IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative).ToString()) | out-null;
}
}
"All done."
#Thanks to:
#"Identifying Object Types": http://powershell.com/cs/blogs/tobias/archive/2008/10/14/identifying-object-types.aspx
#"Exiting early from foreach": http://stackoverflow.com/questions/10277994/powershell-how-to-exit-from-foreach-object
#"Calling functions with multiple parameters" http://stackoverflow.com/questions/4988226/powershell-multiple-function-parameters
When the script runs, files 1,2,3,5,9, and 10 get copied, and file 6 gets overwritten because it is smaller in the destination.
Here is a batch file that sets up your test case (plus some extra folders to test spaces in the names). I have commented out the two lines that clear out directories A and Z for safety but you can remove the REM statements if you are unconcerned about deleting files in a folder A and Z in the current directory.
#ECHO OFF
REM Uncomment at own risk RD /S /Q A
REM Uncomment at own risk RD /S /Q Z
MD "A\B"
echo aaaaaaaabbbbbbbbcccccccc>"A\B\file 1.txt"
echo aaaaaaaabbbbbbbbcccccccc>"A\B\file 2.txt"
echo aaaaaaaabbbbbbbbcccccccc>"A\B\file 3.txt"
MD "A\C"
echo aaaaaaaabbbbbbbbcccccccc>"A\C\file 4.txt"
MD "A\D"
echo aaaaaaaabbbbbbbbcccccccc>"A\D\file 5.txt"
echo aaaaaaaabbbbbbbbcccccccc>"A\D\file 6.txt"
MD "A\FOLDER E"
echo aaaaaaaabbbbbbbbcccccccc>"A\FOLDER E\file 9.txt"
echo aaaaaaaabbbbbbbbcccccccc>"A\FOLDER E\file 10.txt"
MD "Z\Y"
echo aaaaaaaabbbbbbbbcccccccc>"Z\Y\file 8.txt"
MD "Z\C"
echo aaaaaaaabbbbbbbbccccccccdddddddd>"Z\C\file 4.txt"
MD "Z\D"
echo aaaaaaaa>"Z\D\file 6.txt"

Related

Batch list folder, count pdf files and get file name

I would like to create a summary of all the files that I received weekly from other department. The folder structure shown below. Each folder will contain multiples pdf files and only 1 .docx file. So, i would like to list down the folder name, count total pdf files inside and get the name of docx file. If docx missing, show "missing", is this possible too?
I did try this code, but this will show all files in the folder instead.
#echo off
FOR /F "delims=" %%F IN ('dir /B /A /S *') DO (
for %%D in ("%%~dpF\.") do echo/ FolderName: %%~nxD ^| FileName: %%~nxF
)
pause
UPDATE:Today while Im testing suggested code, they send me last week file. AND to my surprised, the other department changed folder structure (facepalm!). Below updated folder structure for reference.
Updated folder structure:
Current
|count.bat
|--FolderA-Folder1-Nov 2020.docx
| -pdf1.pdf
| -pdf2.pdf
| -pdf3.pdf
| -pdf4.pdf
| Folder2-Dec 2020.docx
| -pdf1.pdf
| -pdf2.pdf
| -pdf3.pdf
| -pdf4.pdf
|--FolderB-Folder1-Nov 2020.docx
| -pdf1.pdf
| -pdf2.pdf
| -pdf3.pdf
| -pdf4.pdf
| Folder2-Dec 2020.docx
| -pdf1.pdf
| -pdf2.pdf
| -pdf3.pdf
| -pdf4.pdf
|--FolderC-Folder1-Nov 2020.docx
| -pdf1.pdf
| -pdf2.pdf
| -pdf3.pdf
| -pdf4.pdf
Expectation Results
FolderName: Folder A Folder 1 PDFtotal: 4pdfs DocFile: Nov 2020.docx
FolderName: Folder A Folder 2 PDFtotal: 4pdfs DocFile: Dec 2020.docx
FolderName: Folder B Folder 1 PDFtotal: 4pdfs DocFile: Nov 2020.docx
FolderName: Folder B Folder 2 PDFtotal: 4pdfs DocFile: Dec 2020.docx
FolderName: Folder C Folder 1 PDFtotal: 4pdfs DocFile: Nov 2020.docx
Original Script
The dir command without the /B option displays the count of matching items in the penultimate line, which could be captured and parsed by a for /F loop.
Since you have got a flat directory structure, I would not do a recursive approach (like dir /S or for /R).
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=." & rem // (target directory; `.` is current, `%~dp0.` is parent)
set "_MASK=Doc*.docx" & rem // (pattern to find particular file)
set _LIST="pdf" & rem // (space-separated list of file extensions without `.`)
rem // Loop through immediate sub-directories of the target directory:
for /D %%D in ("%_ROOT%\*") do (
rem // Return name of current sub-directory without trailing line-break:
< nul set /P ="FolderName: %%~nxD "
rem // Loop through given list of file extensions:
for %%E in (%_LIST%) do (
rem // Initialise variables:
set /A "CNT=0, NUM=0" & set "NAME="
rem // Capture number of matching files from last but one line of `dir`:
for /F "eol= " %%C in ('2^> nul dir /A:-D-H-S "%%~D\*.%%~E"') do (
2> nul set /A "CNT=NUM, NUM=%%C"
)
rem // Return count of matching files without trailing line-break:
< nul call set /P ="PDFtotal: %%CNT%%%%~Es "
)
rem // Find file that matches the given pattern (assuming there is only one):
for %%F in ("%%~D\%_MASK%") do set "NAME=%%~nxF"
rem // Return name of found file, with trailing line-break this time:
call echo DocFile: %%NAME%%
)
endlocal
exit /B
The option /A:-D-H-S of the dir command in the code prevents hidden and system files from being counted; change it to /A:-D if you do want to regard them as well.
Updated Script
In the following you will find the new code adapted to your changed directory structure (you will notice that there were only a few modifications necessary):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=." & rem // (target directory; `.` is current, `%~dp0.` is parent)
set "_MASK=* 2020.docx" & rem // (pattern to find particular file)
set _LIST="pdf" & rem // (space-separated list of file extensions without `.`)
rem // Loop through immediate sub-directories of the target directory:
for /D %%S in ("%_ROOT%\*") do (
rem // Loop through next level of sub-directories:
for /D %%D in ("%%~S\*") do (
rem // Return names of current sub-directories without trailing line-break:
< nul set /P ="FolderName: %%~nxS %%~nxD "
rem // Loop through given list of file extensions:
for %%E in (%_LIST%) do (
rem // Initialise variables:
set /A "CNT=0, NUM=0" & set "NAME="
rem // Capture number of matching files from last but one line of `dir`:
for /F "eol= " %%C in ('2^> nul dir /A:-D-H-S "%%~D\*.%%~E"') do (
2> nul set /A "CNT=NUM, NUM=%%C"
)
rem // Return count of matching files without trailing line-break:
< nul call set /P ="PDFtotal: %%CNT%%%%~Es "
)
rem // Find file that matches the given pattern (assuming there is only one):
for %%F in ("%%~D\%_MASK%") do set "NAME=%%~nxF"
rem // Return name of found file, with trailing line-break this time:
call echo DocFile: %%NAME%%
)
)
endlocal
exit /B
#echo off
setlocal enabledelayedexpansion
set "spaces= "
FOR /F "delims=" %%F IN ('dir /B /AD /S *') DO (
rem new foldername in %%F
set "foldername=%%~nxF%spaces%"
set /a pdfcount=0
set /a docxcount=0
set "docxmessage=missing"
for /f "delims=" %%D in ('dir /B /A-D "%%F\*"') do (
if /i "%%~xD"==".pdf" set /a pdfcount+=1
if /i "%%~xD"==".docx" set /a docxcount+=1&set "docxmessage=%%~nxD"
)
set "pdfcount=%spaces%!pdfcount!"
if !docxcount! gtr 1 (set "docxcount= MULTIPLE") else (set "docxcount=")
echo/ FolderName: !foldername:~0,20! PDFtotal: !pdfcount:~-3!pdfs Docfile: !docxmessage! !docxcount!
)
Note that the first dir command now contains AD to list directories only.
With each directoryname, record it in foldername and add some spaces at the end. Reset the counters and establish the missing value in the docxmessage.
Then get the filename list within the directory found, count each .pdf and .docx and if any .docx is found, record its name in docxmessage
Modify docxcount to a message if more than 1 .docx is present, and empty otherwise
When the directory-scan is finished, apply some spaces to the start of pdfcount and then produce your output line using the current values of the variables and using the modifiers to produce the first 20 characters of the padded directoryname and the last 3 characters of the padded pdfcount.
When you use the point-click-and-giggle method of executing a batch, the batch window will often close if a syntax-error is found. You should instead open a 'command prompt' and run your batch from there so that the window remains open and any error message will be displayed.
Fixed : for /F %%D... needed "delims=" to assign the whole filename to %%D
Revised code for new structure:
#echo OFF
setlocal ENABLEDELAYEDEXPANSION
PUSHD U:\sourcedir
set "spaces= "
FOR /F "delims=" %%F IN ('dir /B /AD /S *') DO (
rem new foldername in %%F
set "foldername=%%~nxF%spaces%"
rem find parent directory
FOR /F "delims=" %%Q IN ("%%~dpF\.") DO SET "parent=%%~nxQ%spaces%"
rem is a leaf directory if this directory has no subdirectories
SET "isleaf=Y"
FOR /F "delims=" %%Q IN ('dir /B /AD "%%F"') DO SET "isleaf="
set /a pdfcount=0
set /a docxcount=0
set "docxmessage=missing"
for /f "delims=" %%D in ('dir /B /A-D "%%F\*" 2^>nul') do (
if /i "%%~xD"==".pdf" set /a pdfcount+=1
if /i "%%~xD"==".docx" set /a docxcount+=1&set "docxmessage=%%~nxD"
)
set "pdfcount=%spaces%!pdfcount!"
if !docxcount! gtr 1 (set "docxcount= MULTIPLE") else (set "docxcount=")
IF DEFINED isleaf echo/ FolderName: !parent:~0,20! !foldername:~0,20! PDFtotal: !pdfcount:~-3!pdfs Docfile: !docxmessage! !docxcount!
)
popd
GOTO :EOF
Some small additions to the code.
first, find the parent directoryname. By using the directoryname in %%F and adding \., the resultant resolved string appears to be a filename, the name and extension of which is the parent directory; store this in parent with padding.
Next, determine whether this is a leaf directory. Set the flag isleaf to assume it is a leaf directory, then perform a dir/ad so that any detected subdirectory name will clear the flag.
Then just process the directory as before, using 2^>nul to suppress file not found messages if the directory %%F contains no files.
...And only generate the report line if isleaf is defined, with the parent directoryname added.
This can be placed into a .bat file script and run in cmd.exe. Note that this does not identify directories which contain no .pdf file, no .docx file, or multiple .docx files.
powershell.exe -NoLogo -NoProfile -Command ^
"$Dirs = Get-ChildItem -Directory -Path 'C:\src\t';" ^
"foreach ($Dir in $Dirs) {" ^
" $PdfCount = (Get-ChildItem -File -Path $Dir.fullname -Filter '*.pdf').Count;" ^
" if (($null -ne $PdfCount) -and (0 -ne $PdfCount)) {" ^
" $DocxFiles = (Get-ChildItem -File -Path $Dir -Filter '*.docx');" ^
" if ($null -ne $DocxFiles) { $DocxFile = $DocxFiles[0] } else { $DocxFile = 'none' };" ^
" """FolderName: $($Dir.Name) PDFtotal: $($PdfCount.ToString())pdfs DocFile: $DocxFile""";" ^
" }" ^
"}"
It would be easier to put the script into a file.
=== Get-DocxAndPdfCount.ps1
[CmdletBinding()]
Param()
$Dirs = Get-ChildItem -Directory
foreach ($Dir in $Dirs) {
Write-Verbose "dir is $($Dir.fullname)"
$PdfCount = (Get-ChildItem -File -Path $Dir.fullname -Filter '*.pdf').Count
Write-Verbose $PdfCount
if ($null -ne $PdfCount -and 0 -ne $pdfCount) {
Write-Verbose $PdfCount
$DocxFiles = (Get-ChildItem -File -Path $Dir -Filter '*.docx')
if ($null -ne $DocxFiles) { $DocxFile = $DocxFiles[0] } else { $DocxFile = 'none' }
"FolderName: $($Dir.Name) PDFtotal: $($PdfCount.ToString())pdfs DocFile: $DocxFile"
}
}
Then, run it in a PowerShell console using:
.\Get-DocxAndPdfCount
.\Get-DocxAndPdfCount -Verbose # to see debugging information
Run from cmd.exe using:
powershell -NoLogo -NoProfile -File '.\Get-DocxAndPdfCount'
powershell -NoLogo -NoProfile -File ".\Get-DocxAndPdfCount" -Verbose

Extract list of path in a file using batch script

Here is my text file:
==================================================
Folder : D:\T\New folder
==================================================
==================================================
Folder : D:\T\Z-Ai
==================================================
==================================================
Folder : D:\T\Z-BiN
==================================================
I need to extract the paths from this file, so I have something like this:
D:\T\New folder
D:\T\Z-Ai
D:\T\Z-BiN
It seems I should use findstr TargetWord TargetFile.txt command. and Also it seems I can use regex like this: findstr /r "^[a-z][a-z]$ ^[a-z][a-z][a-z]$"
But I do not know how to loop through found targets or get the list of output. any help is really appreciated.
Based on your comment, you want to use the result to perform an xcopy task, it seems you really want something like this. Note I used example.txt as input file, and DESTINATION where you should add your destination, including the relevant xcopy switches you require:
#echo off
for /f "tokens=2*" %%i in ('type example.txt ^| findstr /i ":\\"') do xcopy "%%~j\*" DESTINATION
Alternatively we can use the findstr directly on Folder
#echo off
for /f "tokens=2*" %%i in ('type example.txt ^| findstr /i "Folder"') do xcopy "%%~j\*" DESTINATION
You can do like this :
#echo off
Title Extract list of path in a file using batch script
set "TxtList=MyList.txt"
Set "OutPutData=Output.txt"
Call :Extract "%TxtList%" "%OutPutData%"
Start "" "%OutPutData%"
Exit
::*****************************************************
:Extract <InputData> <OutPutData>
(
echo Data = WScript.StdIn.ReadAll
echo Data = Extract(Data,"[\w]:(\\[0-9\sA-Za-z\-]*)+"^)
echo WScript.StdOut.WriteLine Data
echo '************************************************
echo Function Extract(Data,Pattern^)
echo Dim oRE,oMatches,Match,Line
echo set oRE = New RegExp
echo oRE.IgnoreCase = True
echo oRE.Global = True
echo oRE.Pattern = Pattern
echo set oMatches = oRE.Execute(Data^)
echo If not isEmpty(oMatches^) then
echo For Each Match in oMatches
echo Line = Line ^& Trim(Match.Value^) ^& vbcrlf
echo Next
echo Extract = Line
echo End if
echo End Function
echo '************************************************
)>"%tmp%\%~n0.vbs"
cscript /nologo "%tmp%\%~n0.vbs" < "%~1" > "%~2"
If Exist "%tmp%\%~n0.vbs" Del "%tmp%\%~n0.vbs"
exit /b
::****************************************************
For Windows. you can use powershell.
select-string -Path c:\tmp\file.txt -Pattern '[A-Z]:(\\[0-9\ A-Za-z\-]*)+' -AllMatches | % { $_.Matches } | % { $_.Value }
In my opinion, For /F is all you need for the task. Although using Type may be useful in some situations, there's no need to use find.exe or findstr.exe for this task as you don't need to match a particular glob/pattern:
#For /F "EOL==Tokens=2*UseBackQ" %%A In ("TargetFile.txt")Do #"%__AppDir__%xcopy.exe" "%%B" "Destination\" /Options
Please note that it may be wise, if there's a chance that one or more of theses Folders do not exist, that you prepend using If Exist "%%B\". Importantly, if each of the lines containing the Folder paths, is space padded up to the end of its line, this solution will not work for you.

Add foldersize to foldername using Batch/vbs file for all subfolders in a directory

Is it possible to add foldersize to foldername using Batch/vbs for all subfolders in a directory?
Example:
I have few subfolders in a directory like,
Name --- Size
Folder1 --- (22.5GB)
Folder2 --- (980.3MB)
Folder3 --- (968.4KB)
Need to change folder names to,
Folder1 [22.5 GB]
Folder2 [980.3 MB]
Folder3 [968.4 KB]
I tried with the following code, it gets the folder sizes in cmd panel but need to know how to add the size to folder name,
#echo off
Title Get Size of Folder and its subfolders
set "Folder=C:\RootFolder\"
For /f "delims=" %%a in ('Dir "%Folder%" /AD /b /s') do (
(
echo The size of "%%a" is
Call :GetSize "%%a"
)
)
For /D %%a in (*) do rename "%%a" "%%a [!GetSize!]"
pause
::*************************
:GetSize
(
echo wscript.echo GetSize("%~1"^)
echo Function GetSize(MyFolder^)
echo Set fso = CreateObject("Scripting.FileSystemObject"^)
echo Set objFolder= fso.GetFolder(MyFolder^)
echo GetSize = FormatSize(objFolder.Size^)
echo End Function
echo '******************
echo 'Function to format a number into typical size scales
echo Function FormatSize(iSize^)
echo aLabel = Array("bytes", "KB", "MB", "GB", "TB"^)
echo For i = 0 to 4
echo If iSize ^> 1024 Then
echo iSize = iSize / 1024
echo Else
echo Exit For
echo End If
echo Next
echo FormatSize = Round(iSize,2^) ^& " " ^& aLabel(i^)
echo End Function
echo '*****************
)>%tmp%\Size.vbs
Cscript /NoLogo %tmp%\Size.vbs
Del %tmp%\Size.vbs
Exit /b
::*********************

Command prompt logging with xcopy

I have an xcopy script that I'm running that reads in a .csv file with directories and file names and parses it to copy the files.
Here's the script:
echo F | for /f "delims=, tokens=1,2,3" %i in (D:\foo.csv)
do xcopy /i /d "Z:\%i\%j\%k" "Y:\%i\%j\%k" >> "D:\xcopy\Log.txt"
The output to the command prompt are the commands being executed:
echo F | xcopy /i /d "Z:\hcri001\a1\
ffce5a14-33ca-43cf-b366-af266c450979" "Y:\hcri001\a1\ffce5a14-33ca-43cf-b366
-af266c450979" 1>>"D:\xopy\Log.txt
However, the log just has the output of the commands:
0 File(s) copied
0 File(s) copied
0 File(s) copied
Does Y:\hcri001\2d\545392db-50fa-40d9-aaa2-0892ca5057f3 specify a file name
or directory name on the target
(F = file, D = directory)? F
Z:\hcri001\2d\545392db-50fa-40d9-aaa2-0892ca5057f3
1 File(s) copied
Is there someway to have both the commands being executed, as well as the output?
Also, is there anyway to have some sort of counter that I can put in the beginning of the line?
My Ideal log file would be in this format:
1) C:\Desktop>echo F | xcopy /i /d "Z:\hcri001\a7\
00a62a73-d7a7-4cfb-b55c-457bc67b3647" "Y:\hcri001\a7\00a62a73-d7a7-4cfb-b55c
-457bc67b3647" 1>>"D:\Robocopy\AtlusPatient131172CopyLog.txt
0 File(s) copied
2) C:\Desktop>echo F | xcopy /i /d "Z:\hcri001\d5\
003452354-d7a7-4cfb-452c-457bc67b3647" "Y:\hcri001\d5\003452354-d7a7-4cfb-452c-457bc67b3647" 1>>"D:\Robocopy\AtlusPatient131172CopyLog.txt
0 File(s) copied
3) C:\Desktop>echo F | xcopy /i /d "Z:\hcri001\2d\545392db-50fa-40d9-aaa2-0892ca5057f3" "Y:\hcri001\2d\545392db-50fa-40d9-aaa2-0892ca5057f3" 1>>"D:\Robocopy\AtlusPatient131172CopyLog.txt
Does Y:\hcri001\2d\545392db-50fa-40d9-aaa2-0892ca5057f3 specify a file name
or directory name on the target
(F = file, D = directory)? F
Z:\hcri001\2d\545392db-50fa-40d9-aaa2-0892ca5057f3
1 File(s) copied
and bonus points if the command can be trimmed to just include the file name instead of the whole command i.e. 1) "Z:\hcri001\2d\545392db-50fa-40d9-aaa2-0892ca5057f3"
0 File(s) copied
for /f "delims=, tokens=1,2,3" %i in (D:\foo.csv) do (
echo xcopy /i /d "Z:\%i\%j\%k" "Y:\%i\%j\%k" >> "D:\xcopy\Log.txt"
echo f | xcopy /i /d "Z:\%i\%j\%k" "Y:\%i\%j\%k" >> "D:\xcopy\Log.txt"
)
For the counter you need SETLOCAL ENABLEEXTENSIONS then set counter=1
and inside the loop set /a counter=!counter! + 1

Batch rename file extensions, including subdirectories

I'm renaming empty file extensions with this command:
rename *. *.bla
However, I have a folder with hundreds of such subfolders, and this command requires me to manually navigate to each subfolder and run it.
Is there a command that I can run from just one upper level folder that will include all the files in the subfolders?
for /r c:\path\ %G in (*.) do ren "%G" *.bla
#echo off
for /f "tokens=* delims= " %%i in ('dir /b/s/A-d') DO (
if "%%~xi" == "" rename "%%~fi" "%%~ni.bla"
)
Thanks #Wadih M. Find and rename files with no extension?
this will allow you to enter dirs with spaces in the names. (note the double % is for batch files, use a single % for command lines.)
for /f "tokens=* delims= " %%a in ('dir /b /ad /s') do rename "%%a\*." "*.bla"
You can easily do this and many more things with the Perl module File::Find.
#!perl
use strict;
use warnings;
use File::Find;
my $extension = 'bla';
my $directory = '/tmp/test';
print "Files renamed:\n";
find( \&wanted, $directory );
sub wanted {
return if /\./;
return unless -f $File::Find::name;
if ( rename( $File::Find::name, "$File::Find::name.$extension" ) ) {
print " $File::Find::name -> $File::Find::name.$extension\n";
}
else {
print " Error: $! - $File::Find::name\n";
}
}
You can use for to iterate over subdirectories:
for /d %x in (*) do pushd %x & ren *. *.bla & popd
When using it from a batch file you would need to double the % signs:
for /d %%x in (*) do pushd %%x & ren *. *.bla & popd
Try this
for /R c:\temp %I in (*. ) DO Echo rename %I "%~nI.bla"
Using find and xargs and basename would make the expression easier to read
Prepare a rename shell script like this (corrected to handle multiple files)
#!/bin/sh
if [ $# -lt 3 ]
then
echo "usage: rename.sh sufold sufnew file1 (file2 file3 ...) "
exit
fi
sufold=$1
sufnew=$2
shift
shift
for f in $*
do
echo "to mv " $f `dirname $f`"/"`basename $f $sufold`$sufnew
mv $f `dirname $f`"/"`basename $f $sufold`$sufnew
done
Then you could invoke that to each file matched your criteria, including recursive folder search by find command
find . -name "*." | xargs rename.sh "." ".bla"
A more common sample
find . -name "*.htm" | xargs rename.sh ".htm" ".html"

Resources