Okay, I think I got it. This was harder to develop as I first thought simply because of Microsoft forgot a switch for command
xcopy.
I used help of the commands
xcopy and
set got by running
xcopy /? and
set /? for writing the first batch file for copying active file to the other location with replacing drive and first directory in path for the target file name.
- Code: Select all
@echo off
set SourceFile=%1
set TargetFile=%SourceFile:C:\parent_folder=D:%
xcopy %SourceFile% %TargetFile% /H /K /R /Y
Most interesting here is the third line where a copy of full source file name (with the perhaps surrounding double quotes) is created whereby the string
C:\parent_folder is replaced by
D: to get the full destination file name.
But there was a problem with this small batch file. While command
copy can be used only if the target directory tree exists, the command
xcopy can be used also if the target directory tree does not exist as
xcopy can create it. But
xcopy asks the user if the target is a file or a directory if the target directory does not exist. Command
xcopy has the switch
/I to tell the command that the target is a directory. But there is no such switch for telling
xcopy that the target is a file.
So I ran a WWW search and found the page
xcopy file, rename, suppress "Does xxx specify a file name..." message where Arnshea posted a good solution for this problem. Putting
echo F | left to the command
xcopy results in answering the question always with character
F for
file.
- Code: Select all
@echo off
set SourceFile=%1
set TargetFile=%SourceFile:C:\parent_folder=D:%
echo F | xcopy %SourceFile% %TargetFile% /H /K /R /Y
But I was not happy with that as if the target file already exists, it is useless to pipe to command
xcopy the character
F. So I changed the batch file once more to this:
- Code: Select all
@echo off
set SourceFile=%1
set TargetFile=%SourceFile:C:\parent_folder=D:%
if exist %TargetFile% (
copy /Y %SourceFile% %TargetFile%
) else (
echo F | xcopy %SourceFile% %TargetFile% /H /K /R /Y
)
That's better, but I was still not happy with this solution. I don't like batch files which depend on language of the operating system.
The character
F is only correct for an English Windows. The command
xcopy on a German Windows XP requires
D for
Datei and
V for
Verzeichnis instead of
F for
File and
D for
Directory as on an English Windows.
So I thought it is better to simply copy the file and if this fails because the target directory tree does not exist, use command
mkdir to create the directory tree and copy the file once again.
Here is the final batch file which I named
CopyFileOrFileList.bat for both of your purposes: copying a single file and copying a list of files.
- Code: Select all
@echo off
if "%1" == "" goto EndBatch
if /I "%1" == "/L" goto ListFile
set SingleFile=yes
:CopyFile
set SourceFile=%1
set TargetFile=%SourceFile:C:\parent_folder=D:%
copy /Y %SourceFile% %TargetFile% 1>nul 2>nul
if errorlevel 1 goto :MakeDir
rem echo Copied %SourceFile%
if "%SingleFile%" == "no" goto :EOF
goto EndBatch
:MakeDir
set SourcePath=%~dp1
set TargetPath=%SourcePath:C:\parent_folder=D:%
mkdir "%TargetPath%"
if not errorlevel 1 copy /Y %SourceFile% %TargetFile% 1>nul
if errorlevel 1 goto NoSuccess
rem echo Copied %SourceFile%
:NoSuccess
if "%SingleFile%" == "no" goto :EOF
goto EndBatch
:ListFile
set SingleFile=no
for /F "usebackq delims=" %%F in ("C:\Temp\ListFile.tmp") do call :CopyFile "%%F"
del "C:\Temp\ListFile.tmp"
:EndBatch
set SingleFile=
set SourceFile=
set SourcePath=
set TargetFile=
set TargetPath=
Explanation for the batch file:With the first command
echo off printing all executed commands to stdout (console window) is disabled. To hide execution of this command the
@ is added left to the command.
The second line is just for security in case of running this batch file by mistake without a parameter, for example when double clicking on this batch file.
The third line makes the decision on first parameter passed to the batch file if it should process a list of files or just a single file passed with full name to the batch file. With
/L as first parameter the batch file processes a list of files. For details on command
if execute in a command prompt window or via
Advanced - DOS Command in UltraEdit the command
if /?In case of a single file a new environment variable with name
SingleFile is defined with value
yes.
Next target file name is created from source file name as explained already at beginning of this post.
ATTENTION: You need to modify the strings C:\parent_folder and D: in line 8 according to your paths.Next the simple
copy command is executed with not really necessary switch
/Y (automatically set by default on using copy from within a batch file in comparison to using copy command outside of a batch file). The standard output of command
copy written to
stdout is redirected with
1>nul to no-man's-land as well as an error message output by command
copy to
stderr with
2>nul. You can remove these 2 redirections if you want ever see what this first copy command does.
If command
copy fails to copy the file for example because of not existing target directory tree, it terminates with a value greater than 0. In this case the batch file continous on block starting with label
MakeDir. Otherwise the file was copied and the batch file can finish with removing all environment variables created by the batch file.
If copying the file failed, first the source path must be extracted from the full file name in double quotes. This can be done with
%~dp1 as explained in help of command
for which can be read by executing
for /?Please note that
%~dp1 returns the drive letter with colon and the directory path ending with a backslash always without double quotes even if the full source name was surrounded by double quotes because of a possible space character in full name. This is important to know for usage of the target path as surrounding double quotes must be added again.
I think, how building the target path from source path doesn't need to be explained a second time.
ATTENTION: Don't forget to change the strings C:\parent_folder and D: on line 16 also according to your paths.Now the command
mkdir can be used to create the target directory tree. Although this should never fail, it could nevertheless happen that making the directory tree fails (target drive does not exist, permission problem) and therefore added one more condition based on errorlevel returned by
mkdir to continue or exit the batch execution.
Now the
copy command is used a second time for copying the file to the other directory. It is on purpose that now
2>nul is not used anymore to redirect an error message to no-man's-land. If
copy command fails a second time to copy the file, the error message of the command should be printed to
stderr.
Before the batch file exits it removes all environment variables defined within the batch file. This is not really necessary for execution of the batch file from within UltraEdit, but it is good practice in case of running this batch file from within a command prompt window or from within another batch file.
For copying multiple files as specified in a list file containing line by line the names of the files to copy with full path, the environment variable with name
SingleFile is defined with value
no.
Then a
for loop is used to read one file name after the other from the list file with fixed name and the commands explained above are executed with each file name. The string
"usebackq delims=" could be removed when removing the double quotes arround list file name
C:\Temp\ListFile.tmp which would be possible here as this file name does not contain a space character. But I don't know which file name and path you want to use for the list file.
ATTENTION: You have to adapt list file name C:\Temp\ListFile.tmp twice in the batch file according to your environment.This loop looks very simple, but is very tricky. The command line processor
cmd replaces by default environment variables already on reading a line instead of accessing their values on execution. The help for command
set describes with two examples where this behavior is a problem. Using environment variables with varying values in a
for loop is one of those cases.
The solution used here is to
call the block starting with
CopyFile and ending above
ListFile like another batch file. This block can be imagined as a pseudo batch file within a batch file or as a batch subroutine. With the environment variable with name
SingleFile on every exit point of the copy file "subroutine" the decision is taken to either jump to real end of the batch file, or emulate an end of file of the pseudo batch file to continue the command execution in the
for loop. I don't know anymore from which webpage I got the information how to do that. I have used that trick already before in one of my batch files.
Okay, that's the batch file. In next post I describe how to make use of it within UltraEdit for copying active file and all open files.