I've got a Windows XP batch script which cleans some directories, but I would like to move the deleted files to trash instead of using plain del
. How is this done?
It looks like the only languages I can use for this is plain batch or Perl.
I've got a Windows XP batch script which cleans some directories, but I would like to move the deleted files to trash instead of using plain del
. How is this done?
It looks like the only languages I can use for this is plain batch or Perl.
Write a VBS script (Original Link) then call it with MyDelScript.vbs
function main()
{
if (WScript.Arguments.length != 1)
{
WScript.Echo("<Insert informative error message here>");
return;
}
var Path = WScript.Arguments(0);
var Shell = WScript.CreateObject("Shell.Application");
var Item = Shell.Namespace(0).ParseName(Path);
Item.InvokeVerb("delete");
}
The Win32::FileOp module has a Recycle
function. From the docs:
Recycle @filenames
Send the files into the recycle bin. You will not get any confirmation dialogs. Returns true if successful.
It can be done like this with plain batch and embedded VBScript. Put the following code into a file called recycle.cmd
:
<!-- : Begin batch script
@echo off
if "%1"=="" (
echo Usage: %~nx0 FILE_TO_RECYCLE[...]
echo This script puts files into the recycle bin
exit /b 1
)
cscript //nologo "%~f0?.wsf" %*
exit /b %errorlevel%
----- Begin embedded wsf script --->
<job><script language="VBScript">
Set app = WScript.CreateObject("Shell.Application")
Set fso = CreateObject("Scripting.FileSystemObject")
For Each arg In WScript.Arguments
If fso.FileExists(arg) Then
Set file = fso.GetFile(arg)
Set folderItem = app.Namespace(0).ParseName(file.Path)
folderItem.InvokeVerb("delete")
Else
WScript.Echo "File not found: " & arg
End If
Next
</script></job>
Example:
echo This file is dirt.> dirt.txt
echo This file is trash.> trash.txt
recycle dirt.txt trash.txt
As you can see the script allows recycling multiple files with one command. It does not suppport the wildcards * and ? though.
The idea of embedding VBScript inside a batch file is taken from dbenham's answer to Is it possible to embed and execute VBScript within a batch file without using a temporary file? (scroll down to UPDATE 2014-04-27).
You could use the "recycle" utility which is part of CmdUtils from MaDdoG Software. From the page listing -
I would suggest you try its various switches before you incorporate it into your script - there is quite a bit of deviation from the default behaviour of the "del" command.
UPDATE: Contrary to my original claim that the following code does not work, it indeed seems to work. I just forgot that the file I wanted to delete was not in $ENV{TEMP}
but a subdirectory of $ENV{TEMP}
. The problem is, the file does not go to the Recycle Bin.
The right solution is to use Win32::FileOp but I am going to leave this script here as an example of how to use Win32::API and Win32::API::Struct. I would appreciate it if anyone can point out what I am doing wrong. For your reference:
SHFileOperation
: http://msdn.microsoft.com/en-us/library/bb762164(VS.85).aspx
LPSHFILEOPSTRUCT
: http://msdn.microsoft.com/en-us/library/bb759795(VS.85).aspx
#!/usr/bin/perl
use strict;
use warnings;
use File::Spec::Functions qw( catfile );
use Win32::API;
Win32::API::Struct->typedef(
SHFILEOPSTRUCT => qw(
HWND hwnd;
UINT wFunc;
LPCTSTR pFrom;
LPCTSTR pTo;
FILEOP_FLAGS fFlags;
BOOL fAnyOperationsAborted;
LPVOID hNameMappings;
LPCTSTR lpszProgressTitle;
)
);
Win32::API->Import(
shell32 => q{ int SHFileOperation( LPSHFILEOPSTRUCT lpFileOp ) }
);
my $op = Win32::API::Struct->new( 'SHFILEOPSTRUCT' );
$op->{wFunc} = 0x0003; # FO_DELETE from ShellAPI.h
$op->{fFlags} = 0x0040; # FOF_ALLOWUNDO from ShellAPI.h
my $to_delete = catfile( $ENV{TEMP}, "test.file" );
$op->{pFrom} = $to_delete . "\0\0";
my $result = SHFileOperation( $op );
if ( $result ) {
warn sprintf "The operation failed: %4.4X\n", $result;
}
else {
if ( $op->{fAnyOperationsAborted} ) {
warn "Operation was aborted\n";
}
else {
warn "The operation succeeded\n";
}
}
__END__