I'm having trouble making a batch file that copies files. Sometimes it says that the directories exist, other times it says that it can not perform a cyclic copy.
#ECHO off
ECHO Please use quotes with directories
ECHO.
IF NOT EXIST Pictures (MD Pictures) > NUL
:start
SET /P From=Copy from:
IF NOT EXIST %From% (ECHO No such directory
ECHO.
goto start)
XCOPY /s %From% Pictures
pause
This is another way to do it: xcopy creates the folder by itself and the slash at the end of the target path stops it from prompting you.
The slash at the if exist "folder\" is used to detect a folder on a local drive, and not a file.
Stephan's answer tells you how to avoid a cyclic copy error.
#ECHO off
ECHO Please use quotes with directories
ECHO.
:start
SET /P From=Copy from:
IF exist "%From%\" (
XCOPY /s %From% "Pictures\"
) else (
ECHO No such directory
ECHO.
goto start
)
pause
if you try to create a directory, that already exists, md tells you. You can suppress it with
md pictures 2>nul
The parameter /s with xcopy tells the computer to copy subdirectories and their content too. So you would make a copy of a copy of a copy of a copy.... (called cyclic copy). To avoid this, don't use /s or make sure, the destination directory is outside the directory-tree, you want to copy.
Related
Can anyone here give me a hint, why my batch script marks successfully processed folders as system, hidden, non-archive? Furthermore I cannot even remove the "hidden" attribute via Explorer (probably because of the systemfolder attribute).
The script is meant to process one folder (passed to it as a parameter), looking for raw-photo files (.nef files in my case) that are marked read-only. For every read-only photo the script copies a specified file to the processed folder and renames that copy according to the photo filename.
The folder attribute mess is caused by robocopy. (Without that command there is no problem.) But it doesn't have to touch the folder at all. It only copies one file to that folder. The error only occurs, if at least one file in the folder was marked read-only and gets a sidecar file.
I already tried to move the script from system drive to desktop and start it from there. It made no difference.
(To avoid confusion: I am on a non-English Windows 10, so I used !var! instead of %var%. Hell it took some time to find that trick...)
echo off
setlocal ENABLEDELAYEDEXPANSION
chcp 65001
IF "%~1" == "" (
GOTO myWarning
) ELSE (
IF EXIST "%~1" (
GOTO myFuction
) ELSE (
GOTO myWarning
)
)
GOTO myFuction
:myWarning
echo Ordner-Pfad muss angegeben werden!
pause
GOTO:eof
:myFuction
echo Bearbeite %1
cd "%1"
for /r %%f in (*.nef) do (
set fileattr=%%~af
set readonlyattr=!fileattr:~1,1!
:: check if current file is read-only
IF !readonlyattr!==r (
:: create XMP-Sidecar file for read-only photos
echo %%f
robocopy "C:" "%1" "metadata-2stars.xmp"
rename "metadata-2stars.xmp" "%%~nf.xmp"
)
)
GOTO:eof
Sorry, after I narrowed the problem down to robocopy I found the solution. It seems to be a known bug in robocopy, e.g. described here:
https://blog.coeo.com/how-to-prevent-robocopy-from-hiding-your-files-and-how-to-fix-it-when-it-does
The solution/hotfix is simply to tell robocopy not to mark the destination as system hidden by adding /A-:SH at the end of the command. So with robocopy "C:" "%1" "metadata-2stars.xmp" /A-:SH everything works as expected.
I am struggling to create a batch file that I can use in any folder, which will copy the current folder and all its contents to another location. The objective is to allow me to make very quick backups of any current folder by running the batch file. Batch files are new to me, but programming isn't. Here is my code.
#echo off
title Copy This Directory
:: get current directory
set startdir=%cd%
echo.startdir = %startdir%
:: copy the test folder
xcopy "%startdir%" "F:\Temp Backup\" /s /y
pause
This copies the files and folders that are inside the source folder to the new destination, but I want to copy the folder itself together with its contents. ie if the batch file is in a folder called "FromFolder", I want "FromFolder" to appear as a folder in "F:\Temp Backup\" and all its contents in "F:\Temp Backup\FromFolder". I've found lots of info about copying files, but nothing about copying a single directory. I can copy a single file, but when I use the same code and change the file name to a folder name, it copies the folder's contents and not the folder itself. Could someone let me know what I have missed please.
#echo off
rem set destination dir
set destDir=C:\tmp\fizz bang
rem get the current dir
set currDir=%cd%
rem set current dir to parent
pushd ..
rem get the parent dir path
set parDir=%cd%
rem replace the parent path part of the dir with the destination
rem see also: https://stackoverflow.com/a/5821366
rem also note the trailing backslash to tell xcopy it's a directory
CALL set destPath=%%currDir:%parDir%=%destDir%%%\
rem copy
xcopy /e "%currDir%" "%destPath%"
rem go back where we started
popd
pause
I decided to go with creating a new folder at the destination and as a second step copying the contents to it. Here's what I did.
#setlocal enableextensions enabledelayedexpansion
#echo off
title Copy This Directory
:: get current directory
#echo off
set startdir=%cd%
set temp=%startdir%
set folder=
:loop
if not "x%temp:~-1%"=="x\" (
set folder=!temp:~-1!!folder!
set temp=!temp:~0,-1!
goto :loop
)
echo.startdir = %startdir%
echo.folder = %folder%
:: Create new folder if needed
md "F:\Temp Backup\%folder%"
:: copy the contents
xcopy "%startdir%\*.*" "F:\Temp Backup\%folder%\" /s /y
pause
endlocal && set folder=%folder%
If you are running the batch file from the directory you want to backup you can literally do this in a handful of lines of code.
#echo off
title Copy This Directory
for %%G in (".") do set folder=%%~nxG
md "F:\Temp Backup\%folder%" 2>nul
xcopy "*.*" "F:\Temp Backup\%folder%\" /s /y
I'm making a batch that edits a document, but in order to edit, it need's to CD it its location. The problem I'm having is that in order to make it portable, I need the command to be able to locate the file's location.
I've tried:
CD C:\Users\%username%\AppData\Roaming\skype\John
CD C:\Users\%username%\AppData\Roaming\skype\%foldername%\config.xml
Any way to get to the location with the config.xml?
You can try with:
FOR /D %%G IN ("%APPDATA%\skype\*") DO IF EXIST "%%~fG\config.xml" (
set correctDir=%%G
goto :foundFile
)
echo File config.xml not found
goto :eof
:foundFile
cd "%correctDir%"
FOR /D iterates over all directories using the %%G variable. %%~fG expands to the full path to the directorie in %%G.
IF EXIST checks if a file exists.
goto :eof exits the script
EDIT: As #Compo pointed out: for portability reasons it is better to use the OS built-in environment variable %APPDATA% instead of C:\Users\%username%\AppData\Roaming.
I am trying to add the dates to copied files from one directory to another directory. This is how it should look like
Original file name: XEsalary.csv
Result file name: XEsalary-2013-02-15.csv
Here is my code:
set REMOTE=U:\
set LOG=C:\Integration\FE\log_test
set PVM=%DATE:~9,4%-%DATE:~6,2%-%DATE:~3,2%
set YY=%DATE:~9,4%
set LOCAL=C:\FTP\VC\test
cd %LOCAL%
xcopy /y /f /v "%LOCAL%\*.csv" "%REMOTE%\" >>%LOG%\%PVM%.log
xcopy /y /f /v "%LOCAL%\*.csv" "%LOCAL%\archive\*.csv"
:: assist with turning this into a for loop
ren %LOCAL%\archive\*.csv %LOCAL%\archive\*%PVM%.csv
echo. >>%LOG%\%PVM%.log
copying works just file. It is the renaming part which is not working. Any help please?
Thx in advance :-)
Using wildcards with RENAME is tricky. There is no good official documentation, but I have experimented and published rules as to how it works: See How does the Windows RENAME command interpret wildcards?
You can accomplish your rename with the following command, as long as none of your file names include dots (the last extension dot is OK).
ren "%LOCAL%\archive\*.csv" ????????????????????-%PVM%*
The number of ? must be greater than or equal to the longest name in the folder.
The result will be incorrect if a file name contains a dot. For example, part1.part2.csv would become part1-2013-02-15.part2.csv.
Another option is to use a FOR loop. You can safely append the date to any file using this technique.
for %%F in ("%LOCAL%\archive\*.csv") do ren "%%F" "%%~nF-%PVM%%%~xF"
BUT, both solutions have a problem if you rerun the process on a later date. New files will be added to the archive, but both new and old archive files will be renamed to the current date. That won't work.
Better to copy and rename the file in one step using a FOR loop as suggested in rojo's answer.
Or better yet, create a new archive folder with the date in the folder name, and then copy the files to the dated archive folder without renaming :-)
set REMOTE=U:\
set LOG=C:\Integration\FE\log_test
set PVM=%DATE:~9,4%-%DATE:~6,2%-%DATE:~3,2%
set YY=%DATE:~9,4%
set LOCAL=C:\FTP\VC\test
cd %LOCAL%
xcopy /y /f /v "%LOCAL%\*.csv" "%REMOTE%\" >>%LOG%\%PVM%.log
md "%LOCAL%\archive\%PMV%
xcopy /y /f /v "%LOCAL%\*.csv" "%LOCAL%\archive\%PVM%"
You might want to include the time in the folder name if the process could be run multiple times in the same day.
Windows doesn't let you rename with a wildcard. You have to name each file in a for loop. Might as well do the renaming as you're copying. Does this do what you intended?
#echo off
setlocal
set REMOTE=U:\
set LOG=C:\Integration\FE\log_test
set PVM=%DATE:~9,4%-%DATE:~6,2%-%DATE:~3,2%
set YY=%DATE:~9,4%
set LOCAL=C:\FTP\VC\test
xcopy /y /f /v "%LOCAL%\*.csv" "%REMOTE%\" >>%LOG%\%PVM%.log
pushd "%LOCAL%"
for %%I in (*.csv) do (
rem Uncomment the following line to log the copy to archive.
rem echo copy "%%I" -^> "%LOCAL%\archive\%%~nI-%PVM%.csv" >>%LOG%\%PVM%.log
copy "%%I" "%LOCAL%\archive\%%~nI-%PVM%.csv">NUL
)
echo. >>%LOG%\%PVM%.log
popd
I have a folder named x with a number of subfolders and files. I want to delete a folder named y that is present in x and all of it's subfolders. The said folder that has to be deleted may or may not contain any files. I believe i can do this using cmd or some kind of batch file but i am a command line new bi and can really use some help.
A simple thing would be to rd the folder's name, which works but i believe there are better ways than removing each folder individually.. like some loop that goes through all the folders.
Thanks
EDIT: Just to clarify, i have y (the folder that needs to be deleted) inside of x, and it can be in any of x's subfolders and at any level of depth. Also i am looking at answers and it may take some time for me to accept any answer. Please bear with me :)
Here is another solution for this commented to describe each part of the script:
#Echo OFF
REM Important that Delayed Expansion is Enabled
setlocal enabledelayedexpansion
REM This sets what folder the batch is looking for and the root in which it starts the search:
set /p foldername=Please enter the foldername you want to delete:
set /p root=Please enter the root directory (ex: C:\TestFolder)
REM Checks each directory in the given root
FOR /R %root% %%A IN (.) DO (
if '%%A'=='' goto end
REM Correctly parses info for executing the loop and RM functions
set dir="%%A"
set dir=!dir:.=!
set directory=%%A
set directory=!directory::=!
set directory=!directory:\=;!
REM Checks each directory
for /f "tokens=* delims=;" %%P in ("!directory!") do call :loop %%P
)
REM After each directory is checked the batch will allow you to see folders deleted.
:end
pause
endlocal
exit
REM This loop checks each folder inside the directory for the specified folder name. This allows you to check multiple nested directories.
:loop
if '%1'=='' goto endloop
if '%1'=='%foldername%' (
rd /S /Q !dir!
echo !dir! was deleted.
)
SHIFT
goto :loop
:endloop
You can take the /p out from in front of the initial variables and just enter their values after the = if you don't want to be prompted:
set foldername=
set root=
You can also remove the echo in the loop portion and the pause in the end portion for the batch to run silently.
It might be a little more complicated, but the code can be applied to a lot of other uses.
I tested it looking for multiple instances of the same foldername qwerty in C:\Test:
C:\Test\qwerty
C:\Test\qwerty\subfolder
C:\Test\test\qwerty
C:\Test\test\test\qwerty
and all that was left was:
C:\Test\
C:\Test\test\
C:\Test\test\test\
FOR /D /R %%X IN (fileprefix*) DO RD /S /Q "%%X"
Take care of using that...
for RD command:
/S Removes all directories and files in the specified directory
in addition to the directory itself. Used to remove a directory
tree.
/Q Quiet mode, do not ask if ok to remove a directory tree with /S
the FOR command is used to loop through a list of files or variables, the options are very easy to memorize, Directory only Recursively.
A problem common to this type of topics is that if there are instances of the target folder at several levels, most methods cause an error because when an high level folder is deleted, all folders below it disappear. For example:
C:\X\Y\subfolder
C:\X\Y\subfolder\one\Y
C:\X\Y\subfolder\two\Y
C:\X\Y\subfolder\three\Y
C:\X\test
C:\X\test\test
Previous example generate a list of 4 folders named Y that will be deleted, but after the first one is deleted the three remaining names no longer exist, causing an error message when they are tried to delete. I understand this is a possibility in your case.
To solve this problem the folders must be deleted in bottom-up order, that is, the innermost folder must be deleted first and the top level folder must be deleted last. The way to achieve this is via a recursive subroutine:
#echo off
rem Enter into top level folder, process it and go back to original folder
pushd x
call :processFolder
popd
goto :EOF
:processFolder
rem For each folder in this level
for /D %%a in (*) do (
rem Enter into it, process it and go back to original
cd %%a
call :processFolder
cd ..
rem If is the target folder, delete it
if /I "%%a" == "y" (
rd /S /Q "%%a"
)
)
exit /B
Although in this particular case the problems caused by other methods are just multiple error messages, there are other cases when this processing order is fundamental.
Make .bat with following:
del /q "C:\Users\XXX\AppData\Local\Temp\*"
FOR /D %%p IN ("C:\Users\XXX\AppData\Local\Temp\*.*") DO rmdir "%%p" /s /q