tags:

views:

109

answers:

3

I have the below "system command" for moving the file. Is it good to use File::Move command or the use the below one. In case if File::Move is better, how can I use it?

system("mv $LOGPATH/test/work/LOGFILE  $LOGPATH/test/done/$LOGFILE") == 0
  or WriteLog(ERROR, "mv command Failed $LOGPATH/test/work/$LOGFILE  status was $?");
+10  A: 

The function you are looking for is in File::Copy:

use File::Copy 'move';
move $x, $y or WriteLog ("move $x, $y failed: $!");

File::Copy is part of the standard distribution of Perl itself.

You can of course use a system ("mv ...") command to do the same thing. The advantages of File::Copy are:

  • It will work across different operating systems, which may be necessary if you're writing something for other people to use;
  • It doesn't expose you to security holes due to passing data to the shell, or portability bugs because the filepath has meta characters and spaces in it like /Library/Application Support/Hi I'm On A Mac/;
  • It is faster: see Schwern's paste. The cost of system swamps everything else. File::Copy::move and rename have about the same cost, so you may as well use the safer move which works across filesystems.
Kinopiko
The other advantage is it doesn't expose you to security holes due to passing data to the shell. Or portability bugs because the filepath has meta characters and spaces in it like `/Library/Application Support/Hi I'm On A Mac/`
Schwern
@Schwern: thanks, I have added that to the answer.
Kinopiko
+1 for Kinopiko for good answer and +1 for Schwern for a great file name (not to mention the correct point)
DVK
`use File::Copy 'mv'; mv …` in order to keep permissions.
daxim
Thanks a lot for the info
Arav
+4  A: 

To add to Kinopiko's otherwise excellent answer, one of the two main reasons to use File::Copy over the system mv command - aside from not-always-relevant-but-still-meaningful portability concern he noted - is the fact that calling a system command forks off at least one child process (and if you do any re-directs, two of them - mv and shell). This wastes a lot of system resources compared to File::Copy.

DVK
I wonder if there are any statistics on what the performance differences are? Without any numbers, I wouldn't add that to my answer, since it might turn out that the system version was actually faster.
Kinopiko
Without a benchmark, its just a guess. http://gist.github.com/466256 DVK guessed correctly, the cost of `system` swamps everything else. `File::Copy::move` and `rename` have about the same cost, so you may as well use the safer `move` which works across filesystems.
Schwern
Oh thanks I have added that to my answer. Unfortunately the edit history got deleted by a later tidyup edit.
Kinopiko
@Schwern - could he fact that move and rename have the same cost be attribute to the fact that the underlying code is smart enough to execute an underlying filesystem rename when it's possible, same as the code in Unix's "mv" command? I must admit to being too lazy to check at 1am :)
DVK
@Schwern - also, while your approach of actually benchmarking is of course the correct ultimate arbiter, the rule of thumb of "the cost of forking significantly exceeds most other costs" is very rarely one that misfires, at least when dealing with properly coded Perl core modules.
DVK
@DVK The opposite is usually the case. Perl is slow compared to compiled C programs. Unless the thing being done is so small as to be insignificant, such as a rename, the C code will win. For example, Perl's grep vs command line grep. For anything more than a trivial file, command line grep wins hands down. http://gist.github.com/467114 YMMV from situation to situation, but that's the whole point.
Schwern
Thanks a lot for the info.
Arav
+7  A: 

Here's one more thing to add to the mix -- if you're moving the file within the same device (that is, there is no need to move the file contents, only update its directory entry), you can simply use the builtin function rename:

rename OLDNAME,NEWNAME

Changes the name of a file; an existing file NEWNAME will be clobbered. Returns true for success, false otherwise.

Behavior of this function varies wildly depending on your system implementation. For example, it will usually not work across file system boundaries, even though the system mv command sometimes compensates for this. Other restrictions include whether it works on directories, open files, or pre- existing files. Check perlport and either the rename(2) manpage or equivalent system documentation for details.

For a platform independent "move" function look at the File::Copy module.

Ether