Как я могу приостановить обработку Perl без жесткого кодирования продолжительности?

StackOverflow https://stackoverflow.com/questions/884668

  •  23-08-2019
  •  | 
  •  

Вопрос

У меня есть Perl-скрипт, содержащий этот фрагмент кода, который вызывает системную оболочку для получения некоторых файлов с помощью SFTP и распаковки их с помощью WinZip:

#  Run script to get files from remote server
system "exec_SFTP.vbs";

#  Unzip any files that were retrieved
foreach $zipFile (<*.zip>) {
    system "wzunzip $zipFile";
}

Даже если некоторые файлы извлекаются, они никогда не разархивируются, потому что к моменту извлечения файлов и закрытия SFTP-соединения Perl-скрипт уже завершил этап распаковки, в результате чего он не находит ничего для распаковки.

Мое краткосрочное решение состоит в том, чтобы вставить

sleep(60);

перед этапом распаковки, но это предполагает, что SFTP-соединение завершится в течение 60 секунд, что иногда может быть сильно завышенной оценкой, а в других случаях - заниженной.

Есть ли более надежный способ заставить Perl приостановиться до тех пор, пока SFTP-соединение не будет закрыто, прежде чем приступить к этапу распаковки?

Редактировать:Респонденты поставили под сомнение (и вполне обоснованно) использование скрипта VB вместо того, чтобы передавать файлы на Perl.Это связано с безопасностью - скрипт VB поддерживается другими пользователями и авторизован для выполнения SFTP.

Это было полезно?

Решение

Проверьте код в вашем файле *.vbs.В system функция ожидает завершения дочернего процесса, прежде чем продолжить выполнение.Похоже, что ваш файл * .vbs разветвляет фоновую задачу для выполнения FTP и немедленно возвращается.

Другие советы

В идеальном мире ваш скрипт был бы переписан для использования Сеть::SFTP::Иностранный и Архив::Извлечь..

Уродливым способом быстрого взлома может быть создание сенсорного файла перед вашим первым системным вызовом, изменение вашего скрипта для извлечения sftp, чтобы удалить файл, как только это будет сделано, и некоторое время примерно так

while(-e 'touch.file') {
    sleep 5;
}

# foreach [...]

Конечно, вам нужно было бы позаботиться о том, чтобы ваш .vbs вышел из строя и оставил файл touchfile не удаленным, а также о многих других неприятных побочных эффектах.Это было бы для быстрого решения (если ни одно из других предложений не сработает), пока у вас не будет времени переписать без вызовов system().

Вам нужен способ для Perl дождаться завершения передачи SFTP, но поскольку ваш скрипт в данный момент написан, Perl не имеет возможности узнать об этом.(Похоже, вы объединяете как минимум два языка сценариев и (графический интерфейс?) SFTP-клиент;это может сработать, но это не совсем надежно.Зачем использовать VBScript для запуска передачи SFTP?)

Я могу придумать четыре варианта:

  1. Ваш Perl-скрипт мог бы сам выполнять передачу SFTP, используя что-то вроде CPAN's Сеть::SFTP модуль, а не порождает внешнее задание, статус которого он не может отслеживать.
  2. Ваш Perl-скрипт может создать утилиту SFTP командной строки (например PSFTP ( ПСФТП )), который не возвращается до тех пор, пока передача не будет завершена.
  3. Или измените скрипт exec_SFTP.vbs так, чтобы он не возвращался до завершения передачи.
  4. Если вы в настоящее время используете графический SFTP-клиент и по какой-либо причине не можете переключиться, я бы рекомендовал использовать язык сценариев типа Автоматический запуск вместо Perl.AutoIt имеет функции для ожидания изменения состояния Windows и так далее, поэтому ему легче отслеживать завершение действия.

Варианты 1 или 2 были бы наиболее надежными.

Лучшее, что я могу предложить, - это изменить exec_SFTP.vbs так, чтобы он завершал работу только после завершения передачи файла. system ожидает завершения вызванной им программы, так что это должно решить вашу проблему:

       system LIST
       system PROGRAM LIST
               Does exactly the same thing as "exec LIST", except
               that a fork is done first, и родительский процесс
               ожидает завершения дочернего процесса.

Если вы не можете изменить сценарий vbs, чтобы он оставался активным до его завершения, возможно, вы сможете отслеживать создание подпроцесса.Если вы получаете идентификаторы подпроцессов, вы можете отслеживать их, тем самым узнавая, когда завершаются различные дочерние элементы vbs.

Win32::Процесс::Информация позволяет вам получить идентификаторы подпроцессов из запущенного процесса.

Может быть, это глупый вопрос, но почему бы просто не использовать Сеть::SFTP и Архив::Извлечь Модули Perl для загрузки и распаковки файлов?

system не вернется до тех пор, пока не вернется оболочка, в которой выполняется команда;это может быть неверно для запуска графических программ и ассоциаций файлов.

Посмотрите, поможет ли что-нибудь из следующего?

system('cscript exec_SFTP.vbs');

use Win32::Process;
use Win32;
Win32::Process::Create(my $proc, 'wscript.exe',
        'wscript exec_SFTP.vbs', 0, NORMAL_PRIORITY_CLASS, '.');
$proc->Wait(INFINITE);

Взгляните на IPC::Open3

IPC::Open3 - открыть процесс для чтения, записи и обработки ошибок с помощью open3()

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top