Я знаю, что это старый вопрос, но я решил поставить свое решение здесь, так как я работаю над тем же. Ваша идея с пакетом - мой путь, но небольшое изменение, которое я сделал, заключалось в использовании exec()
вместо system()
, так как первый (согласно this ) "... выполняет системную команду и никогда не возвращает", что, похоже, освобождает запущенный процесс. Похоже, что это работает как при запуске интерпретированных файлов Perl со Strawberry Perl, так и при запуске скомпилированных программ с PAR::Packer
.
Я создал test.pl
, который в конечном итоге был скомпилирован в test.exe
, следующим образом:
#!/usr/bin/perl
use 5.10.0;
use strict;
use warnings;
my $batch_file = <<"BATCH";
rem ### IT IS SAFE TO DELETE THIS FILE ###
\@echo off
ping 127.0.0.1 -n 2 -w 1000 > nul
echo Copying over update file...
copy testfile.exe test.exe
BATCH
open my $fh, '>', 'update.bat';
print $fh $batch_file;
close $fh;
exec( 'update.bat' );
testfile.exe
является резервной «обновленной» версией test.exe
, просто чтобы убедиться, что я могу перезаписать test.exe
, пока она работает, и могу. ping
- это способ сделать паузу на 2 секунды, чтобы убедиться, что у процесса был шанс выйти, прежде чем пытаться перезаписать файл.
Как ни странно, созданный пакетный файл update.bat
не может удалить себя, хотя пакетные файлы обычно могут удалять сами. Если я создаю командный файл с этим:
start /b "" cmd /c del %0
Он удалит себя без ошибок. Но если я включу этот фрагмент в update.bat
, он будет жаловаться, что The process cannot access the file because it is being used by another process.
Я не уверен, почему. Поскольку это не особенно важно в моем приложении, я не преследовал это. Я просто оставляю update.bat
и позволяю перезаписать его при следующем обновлении. Но я отмечаю в файле, что его можно безопасно удалить, если кто-нибудь взглянет на него позже.