Используйте fork (). Я добавил дополнительные вызовы sleep (), чтобы вы могли видеть, что процессы работают и работают. На практике обновление crontab, вероятно, будет выполняться достаточно быстро, чтобы цикл монитора вообще не запускался или выполнялся только один раз. Я использовал «разве что (...)», потому что мне кажется, что код стал понятнее; следует помнить, что fork () возвращает pid родительскому элементу и ноль дочернему. Процесс, который не видит pid, поэтому является подпроцессом. (Как уже указывалось, в случае сбоя разветвления вилка вернет undef, и код будет выполняться в исходном процессе. В нашем случае это будет просто означать, что мониторинг запускается после завершения записи, поэтому единственным что мы теряем, так это мониторинг.)
my $file = "/tmp/.$$.crontab.txt";
my $crontab = <<EOS;
# Crontab lines here. Inserted at @{[scalar localtime()]}
EOS
my ($writer_pid, $monitor_pid);
$|++;
# Open file BEFORE launching processes. The monitor depends on the file's
# presence or absence, so if we opened it in the writer process, there'd be a
# chance the monitor process would check before we created it, and exit without
# monitoring.
die "Cannot open temp file\n" unless open(WRITE, ">" . $file);
# Crontab file handle gets passed to the forked process, so we can just use it.
# Altered so we can see the process do its thing.
unless ($writer_pid = fork()) {
print WRITE $crontab."\n";
close WRITE;
print("crontab -l |grep -v backup >> $file");
sleep 20;
print("crontab $file");
sleep 10;
unlink($file);
print "done!\n";
exit;
}
# Either file will exist, or the previous process will
# have completed. If it exists, we monitor. If not,
# we exit immediately.
unless ($monitor_pid = fork()) {
# Child: monitor the writer.
my $waitcount = 1;
while ( -e $file ) {
sleep 2;
print "($waitcount) installing crontab...";
$waitcount++;
}
print "installed\n";
exit;
}
waitpid($monitor_pid, 0);
waitpid($writer_pid,0);
print "both processes done\n";