file copy

file copy ?-force? ?--? source target
file copy ?-force? ?--? source ?source ...? targetDir

The first form makes a copy of the file or directory source under the pathname target. If target is an existing directory, then the second form is used. The second form makes a copy inside targetDir of each source file listed. If a directory is specified as a source, then the contents of the directory will be recursively copied into targetDir. Existing files will not be overwritten unless the -force option is specified. When copying within a single filesystem, file copy will copy soft links (i.e. the links themselves are copied, not the things they point to). Trying to overwrite a non-empty directory, overwrite a directory with a file, or a file with a directory will all result in errors even if -force was specified. Arguments are processed in the order specified, halting at the first error, if any. A -- marks the end of switches; the argument following the -- will be treated as a source even if it starts with a -.


Trap: For soft-links this command copies the link and not the file the link refers to. Example:

 # touch a ; ln -s a b
 # ls -l a b
 ... 0 a
 ... 1 b -> a
 # tclsh
 % file copy b c ; exit
 # ls -l a b c
 ... 0 a
 ... 1 b -> a
 ... 1 c -> a

Question: How do I recursively copy from one directory structure to another that already exists?

file copy will not recursively overwrite:

 % file copy -force /home/path1/dirs /home/path2
 % file copy -force /home/path1/dirs /home/path2
 error copying "/home/path1/dirs" to "/home/path2/dirs": file already exists

Contrast with the following UNIX command that does not raise an error:

 # cp -rf /home/path1/dirs/* /home/path2/dirs

gaoithe: It was not obvious to me how to properly check for file copy error. One simply catches calls to file copy (same for other file commands such as stat).

if {[catch {file copy -force $sFrom $sTo} sError]} {
   FAIL "file copy failed: err:$sError to:$sTo"
}

AMG: In Tcl 8.6, running [file copy] with no arguments produces this error message:

wrong # args: should be "file copy ?-option value ...? source ?source ...? target"

Only two possible options are defined, -force and --, and neither takes an argument. Additionally, --, if specified, must be the last option. So I think the error message should instead be:

wrong # args: should be "file copy ?-force? ?--? source ?source ...? target"

I'm not sure if this is considered a bug. The behavior is technically correct but could be improved. So I'm reporting it here rather than on the bug tracker. I haven't checked the source, but it could be that [file copy] shares the Tcl_WrongNumArgs() invocation with lots of other commands in the ensemble, and there aren't enough hooks to customize the option descriptions. If that's the case, "fixing" this could well be more trouble than it's worth.