Description:
I want to use a syntax like COMP I:\folder1 Z:\folder2 to compare all files in my I drive with the content of my z drive. I only need to compare their names to see if one exsists in the other. I need to recurse into the subdirectories because there are many located in both drives, I understand I need to use a batch script using a FOR loop and the PUSHD and POPD command.
QUESTION:
How do I do this?
From the output from FOR /?
FOR /R [[drive:]path] %variable IN (set) DO command [command-parameters]
Walks the directory tree rooted at [drive:]path, executing the FOR
statement in each directory of the tree. If no directory
specification is specified after /R then the current directory is
assumed. If set is just a single period (.) character then it
will just enumerate the directory tree.
So you'd do something like
#echo off
setlocal enabledelayedexpansion ENABLEEXTENSIONS
for /R P:\ %%F in (*.*) DO (
set fileFull=%%~fF
set filePath=%%~pF
set fileDrive=%%~dF
set fileName=%%~nF
set fileExtension=%%~xF
call :checker "!filePath!" "!fileName!" "!fileExtension!"
)
goto :eof
:checker
set fileTarget="c:%~1%~2%~3"
if not exist %fileTarget% echo %fileTarget% not found
goto :eof
In this case, the script is getting all the filenames in P:\ and its subdirectories and telling me if the file doesn't exist on the same path in C:
List folder differences over a tree:
This uses robocopy to create the list - don't remove /L as this switch makes robocopy only list the information.
robocopy "d:\source\folder one" "c:\target\folder two" /L /fp /njs /njh /ndl /ns /np /mir
If you really need to avoid third party utilities:
#ECHO OFF
SET FOLDER1=I:\Folder1\
SET FOLDER2=Z:\Folder2\
ECHO SET FNAME=%%1 ^& #ECHO %%FNAME:%FOLDER1%=%%^>^>FILES1.TXT>FILES1.BAT
ECHO SET FNAME=%%1 ^& #ECHO %%FNAME:%FOLDER2%=%%^>^>FILES2.TXT>FILES2.BAT
IF EXIST FILES1.TXT DEL FILES1.TXT
IF EXIST FILES2.TXT DEL FILES2.TXT
FOR /F "tokens=*" %%* IN ('DIR /S /B /ON "%FOLDER1%"') DO CALL FILES1.BAT "%%*"
FOR /F "tokens=*" %%* IN ('DIR /S /B /ON "%FOLDER2%"') DO CALL FILES2.BAT "%%*"
ECHO Files from "%FOLDER1%" which are not found in "%FOLDER2%"
FOR /F "tokens=*" %%* IN (FILES1.TXT) DO (FIND %%* FILES2.TXT >NUL || ECHO %%*)
ECHO Files from "%FOLDER2%" which are not found in "%FOLDER1%"
FOR /F "tokens=*" %%* IN (FILES2.TXT) DO (FIND %%* FILES1.TXT >NUL || ECHO %%*)
Related
SETLOCAL enabledelayedexpansion
(
FOR /f "delims=" %%a IN ('dir /ad /b /S "*-ABC*"') DO (
REM Get the foldername without the path name and without the extension (i.e. Folder1-ABC)
SET "eir_foldername=%%~na"
echo "!eir_foldername!"
REM Remove "-ABC" from the filename (i.e. Folder1)
SET "reg_foldername=!eir_foldername:-EIR=!"
echo "%%~dpa" "!reg_foldername!"
rem for /D /r %%~dpa!reg_foldername! in (*) do rmdir /q /s %%~dpa!reg_foldername!
for /D /r %%i in (%%~dpa!reg_foldername!) do echo %%i
Rename "%%~dpa" "!reg_foldername!"
REM Rename the file (with full path and filename) to the new filename (that does not have "-Eir" in it + the original extension)
)
)
echo Successfully renamed!
rem Endlocal
Endlocal
pause
:end
I have a path which contains various folders with the same name. For example, in the pash C:/Test/First/Second/, I have folders Folder1, Folder1-ABC, Folder2, Folder2-ABC.
What I am trying to do is to remove the folders without -ABC and rremove -ABC if a folder name contains it, for example Folder1-ABC should become Folder1).
#echo off
for /f "delims=" %%A in ('dir /ad /b /s ^| findstr /i /v "\-ABC$"') do (
if /i exist "%%~A-ABC\" (
echo rd /q /s "%%~A"
echo move "%%~A-ABC" "%%~A"
)
)
pause
With paired folder names i.e. name and name-ABC, you are looking for the latter name and removing -ABC from the name. It would be perhaps be easier to append -ABC than to remove -ABC.
findstr with /v will print lines that do not match -ABC at the end of line, due to use of $ anchor. Now each path processed in the loop appends -ABC to %%A to check if the paired name does exist. If it does, then the rd and move commands will execute.
The echo command infront of rd and move are for testing. If satisfied is OK, remove the echo commands.
I am trying to write a batch script that recursively lists all directories and their files with *.js type in the below format:
For example, if I start with the C:\project directory
c:\project
project.js
project_time.js
c:\project\core
core.js
core_render.js
core_application.js
I tried to implement the above logic in code as follows:
#echo off
for /r %%f in (*.js) do (
echo %%f >> names.txt
)
pause
I was not able to print the directory under which the files are listed.
#echo off
setlocal disabledelayedexpansion
set "lastdir="
( for /r %%A in (*.js) do (
set "nextdir=%%~dpA"
setlocal enabledelayedexpansion
if /i not "!lastdir!" == "!nextdir!" (
rem Empty line and directory path.
if defined lastdir #echo(
#echo !nextdir!
)
endlocal
rem Filename.
#echo %%~nxA
set "lastdir=%%~dpA"
)
) > "names.txt"
The lastdir variable is to record the last directory path so it is echoed only once.
If lastdir is different to %%~dpA:
If lastdir is defined, then an empty line will be echoed.
Directory path of found file is echoed.
Filename is always echoed.
for modifiers dp is the drive and path. nx is the name and extension.
setlocal enabledelayedexpansion is used only where needed so paths with ! are not vulnerable.
I am not going to suggest a command line solution as it would be very long. Instead suggest use of tree command if the output format is suitable.
Here's an untested example, (I'm not expecting it to be quick if your base directory is large):
#Echo Off
(
For /F "Delims=" %%G In ('Dir /B /S /A:D "C:\Project" 2^> NUL') Do (
%__AppDir__%where.exe /Q "%%G":*.js 1> NUL 2> NUL
If Not ErrorLevel 1 (
Echo/
Echo %%G
For /F "EOL=| Delims=" %%H In ('%__AppDir__%where.exe "%%G":*.js')Do (
Echo %%~nxH
)
)
)
) 1> "names.txt"
Pause
If you prefer to run something from the Command Prompt, then try this version:
(For /F "Delims=" %G In ('Dir /B/S/AD "C:\Project" 2^>NUL')Do #(%__AppDir__%where.exe /Q "%G":*.js >NUL 2>&1&&(Echo/&Echo %G&For /F "EOL=|Delims=" %H In ('%__AppDir__%where.exe "%G":*.js')Do #Echo %~nxH)))>"names.txt"
Two simple ways to do this:
dir /S *.js
You get the answers, just as you requested.
FORFILES /S /M *.js /C "cmd /c echo #path"
You get complete path for every file.
I have a folder containing several hundred sub-folders in the format Name, ID. Each of these folders contain several sub folders, some of which contain spaces in their names. I would like to rename only the sub folders and not the parent folders by replacing the spaces with underscores, e.g. C:\Location\John, 1234\My Documents to C:\Location\John, 1234\My_Documents.
I have tried modifying a piece of script I have found on here but it changes the parent folder as well
Here is the unedited code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "StartFolder=C:\Tydelik"
cd /D %SystemRoot%
set "RenameError="
rem Rename all folders containing at least one space character in folder name.
for /F "delims=" %%I in ('dir "%StartFolder%\* *" /AD /B /S 2^>nul') do call :RenameFolder "%%I"
if defined RenameError echo/& pause
rem Restore initial environment and exit this batch file.
endlocal
goto :EOF
:RenameFolder
set "NewFolderName=%~nx1"
set "NewFolderName=%NewFolderName: =_%"
set "FolderPath=%~dp1"
if not exist "%FolderPath%" set "FolderPath=%FolderPath: =_%"
set "FullFolderName=%FolderPath%%~nx1"
if not exist "%FullFolderName%\" set "RenameError=1" & goto :EOF
for %%J in ("%FullFolderName%") do set "FolderAttributes=%%~aJ"
if "%FolderAttributes:~3,1%" == "h" %SystemRoot%\System32\attrib.exe -h "%FullFolderName%"
ren "%FullFolderName%" "%NewFolderName%" 2>nul
if errorlevel 1 goto ErrorFolderRename
if "%FolderAttributes:~3,1%" == "h" %SystemRoot%\System32\attrib.exe +h "%FolderPath%%NewFolderName%"
goto :EOF
:ErrorFolderRename
echo Error renaming folder "%FullFolderName%"
set "RenameError=1"
if "%FolderAttributes:~3,1%" == "h" %SystemRoot%\System32\attrib.exe +h "%FullFolderName%"
goto :EOF
As I said the expected output for each sub folder should be C:\Location\John, 1234\My_Documents instead of C:\Location\John, 1234\My Documents. Currently with the code I have, I get C:\Tydelik\John,_1234\My_Documents.
While Compo's solution renames folders "depth=2", this renames just the "leafes" (very last folders of a tree, "depth=last"). I kept your call approach to avoid delayed expansion and resulting possible problems (folder names with ! - unlikely in your situation, but one never knows...)
#echo off
setlocal
set "sourcedir=..\..\"
for /f "delims=" %%I in ('dir "%sourcedir%" /ad /b /s 2^>nul') do call :RenameFolder "%%I"
goto :eof
:RenameFolder
dir /ad /b /s "%~1" 2>nul | find /v "" >nul && goto :eof ::skip renaming, if a subfolder exists
set "leaf=%~nx1"
ECHO ren "%~1" "%leaf: =_%"
goto :eof
Note: for security reasons I disabled the ren command by just echoing it. If it works as intended, remove the ECHO.
Here's an example of what I think you're looking for, based upon the fact that you're interested only in renaming subdirectories of "C:\Tydelik\Name, ID", not any contained within those subdirectories:
#Echo Off
SetLocal DisableDelayedExpansion
Set "SourceDir=C:\Tydelik"
For /F "EOL=?Delims=" %%A In ('Dir /B/AD "%SourceDir%" 2^>NUL'
)Do Set "TargetDir="&For /F "EOL=?Delims=" %%B In (
'Dir /B/AD "%SourceDir%\%%A" 2^>NUL') Do (Set "TargetDir=%%B"
SetLocal EnableDelayedExpansion
If Not "!TargetDir: =!"=="!TargetDir!" (
Ren "%SourceDir%\%%A\%%B" "!TargetDir: =_!")
EndLocal)
How to count files in a folder and subfolder files also. folder name and file count and sub folder name and file count.
Ex:
test1 : 2
test1\test11 :3
newfolder : 5
newfolder : 10
like this.
robocopy "x:\target\folder" "x:\target\folder" /l /nocopy /is /e /nfl /njh /njs
or
pushd "x:\target\folder" && (
robocopy . . /l /nocopy /is /e /nfl /njh /njs
popd
)
This will simply call robocopy, but instead of copying anything, we will request that nothing will be copied and only return the list of what should be processed (/nocopy /l). We request to copy from the current folder (a previous pushd command is used) to the current folder, including identical files in the process (/is), processing empty subfolder (/e, to include folders with 0 files), but only process two levels (/lev:2 the current folder and the one below), without generating a file list (/nfl), no job header (/njh) and no job summary (/njs)
The result will be the same list but with the folder name and the number of files in changed columns
To keep the original output format
#echo off
setlocal enableextensions disabledelayedexpansion
pushd "x:\target\folder" && (
for /f "tokens=1,*" %%a in ('
robocopy . . /l /nocopy /is /e /nfl /njh /njs
') do echo %%~fb : %%a
popd
)
This will use a for /f to process the previous robocopy command, splitting the line in two tokens, the first will contain the number of files and will be stored in %%a, and the second the rest of the line and will be stored in %%b. For each line in the output of the inner robocopy command, the code in the do clause is executed: just echo to console the two tokens in reverse order.
If robocopy can not be used (OS older than Vista), then
#echo off
setlocal enableextensions disabledelayedexpansion
for /d /r "x:\target\folder" %%a in (*) do for /f "tokens=1,5" %%b in ('
dir /a-d "%%~fa.\*" 2^> nul ^| findstr /b /c:" " ^|^| echo 0
') do if "%%c"=="" echo %%~fa : %%b
This will
For each folder under the start directory (for /r /d) grab a reference and store it in %%a replaceable parameter
Run a dir command with the full path of the folder %%~fa
Use a pipe (|) to filter the list to only retrieve the lines that start with two spaces (the footer lines)
If no lines are found (that is, the dir command failed) output a 0
The lines generated by the dir | findstr are handled with a for /f command. We will read the first token (the number of files in the adecuated line) and the fifth (only present in the footer line with the directories info)
If the fifth element is empty, this line has information about the files, not the folders, so, echo the folder path and the files inside it
At the end, restore the previous active directory
The problem with this approach is that the dir | findstr is executed for each of the subfolders. This will make this slower than the robocopy solution.
It can be faster, but more code is needed
#echo off
setlocal enableextensions disabledelayedexpansion
set "root=%cd%"
set "folder="
for %%r in ("%root%") do (
set "rootDrive=%%~dr\"
if not defined rootDrive set "rootDrive=\\"
for /f "delims=" %%a in ('
dir /s /a "%%~fr.\*" 2^>nul ^| findstr /r /c:"^ " /c:"^ .*\\."
') do for /f "tokens=1,* delims=\" %%b in ("%%~a") do if not "%%c"=="" (
set "folder=%%c"
) else if defined folder (
for /f %%d in ("%%~a") do (
setlocal enabledelayedexpansion
echo(!rootDrive!!folder! : %%d
endlocal
)
set "folder="
)
)
In this case, we will execute only one dir command to retrieve the full list and filter with findstr the list to only retrieve the lines with the name of the folder and the footer for each folder.
The code will iterate (for /f %%a) over this list. When a folder line is found (it contains a backslash and can be splitted by the for /f %%b), the folder name is saved in a variable. When the corresponding footer line is readed (it was not splitted by a backslash), the line is splitted to get the number of files (for /f %%d) and the folder name and the number of files are echoed to console (here delayed expansion is needed to retrieve the variable contents, as they were set inside the same loop)
Note: Using a for /f to process a large list of data generated by executing a command can be really slow (there is a bad behaviour in how the command handles memory). For this cases it is necessary to first execute the command that generates the data (dir | findstr in this case) sending its output to a file and then use the for /f to process the file.
#echo off
setlocal enableextensions disabledelayedexpansion
set "root=%~1"
if not defined root for %%a in (.) do set "root=%%~fa"
set "folder="
for %%t in ("%temp%\%~nx0.%random%%random%.tmp") do for %%r in ("%root%") do (
set "rootDrive=%%~dr\"
if not defined rootDrive set "rootDrive=\\"
( dir /s /a "%%~fr.\*" 2^> nul | findstr /r /c:"^ " /c:"^ .*\\." ) > "%%~ft"
for /f "usebackq delims=" %%a in ("%%~ft") do (
for /f "tokens=1,* delims=\" %%b in ("%%~a") do if not "%%c"=="" (
set "folder=%%c"
) else if defined folder (
for /f %%d in ("%%~a") do (
setlocal enabledelayedexpansion
echo(!rootDrive!!folder! : %%d
endlocal
)
set "folder="
)
)
del /q "%%~ft"
)
edited to adapt to comments: robocopy solution changed to include total number of files
#echo off
setlocal enableextensions disabledelayedexpansion
set "total=0"
pushd "x:\target\folder" && (
for /f "tokens=1,*" %%a in ('
robocopy . . /l /nocopy /is /e /nfl /njh /njs
') do (
echo %%~fb : %%a
set /a "total+=%%a"
)
popd
)
echo Total files: %total%
After successfully removing a bunch of Google Drive Folder duplicates, some files retain a "filename(2)"name.
Is there a way to batch rename every file so the parenthesis and the number inside the parenthesis is gone?
That includes folders and sub-folders.
Try like this :
Create a file test.bat with the code below in it and replace the path to test in the var $path
#echo off
set $path="C:\Users\CN Micros\Desktop\PROGRAMMATION\test"
for /f "tokens=1-3 delims=^(^)" %%a in ('dir /b/a-d %$path%') do (
if exist %$path%\"%%a(%%b)%%c" echo ren %$path%\"%%a(%%b)%%c" "%%a%%c"
)
pause
Then run it in the CMD or by double clicking.
If the output is ok for you remove the echo
The program create 3 tokens : %%a = what's before the (), %%b What's inside the () and %%c what's after the ().
Then we arrange this 3 tokens to rename the files without the ().
If you have some file who have the same final name ie : "file(1)name", "file(2)name" --> "filename"
It will work only with the first one. If you have this case you have to add a counter at the end of file to be sure that they will be renamed.
This will create renfiles.bat.txt for you to examine in Notepad and then rename to .bat and execute if you are happy with it.
#echo off
dir /b /a-d *(*).* |find /i /v "%~nx0" |find /i /v "repl.bat" |repl "(.*)\(.*\)(\..*)" "ren \q$&\q \q$1$2\q" xa >"renfiles.bat.txt"
This uses a helper batch file called repl.bat - download from: https://www.dropbox.com/s/qidqwztmetbvklt/repl.bat
Place repl.bat in the same folder as the batch file or in a folder that is on the path.
Edit: This version will recurse through subdirectories:
#echo off
dir /b /s /a-d *(*).* |find /i /v "%~nx0" |find /i /v "repl.bat" |repl ".*\\(.*)\(.*\)(\..*)" "ren \q$&\q \q$1$2\q" xa >"renfiles.bat.txt"
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR /f "delims=" %%a IN (
'dir /b /s /a-d "%sourcedir%\*" '
) DO (
SET "name=%%~na"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "newname=!name:)=!"
SET "newname=!newname:(=!"
IF "!name!" neq "!newname!" (
IF EXIST "%%~dpa!newname!%%~xa" (ECHO cannot RENAME %%a
) ELSE (ECHO(REN "%%a" "!newname!%%~xa")
)
endlocal
)
GOTO :EOF
You'd need to set your required directory into sourcedir. I used u:\sourcedir which suits my testing.
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.