我必須運行Bash命令。但是這個命令需要幾分鐘才能運行。從Perl腳本異步執行Bash命令
如果我正常(同步)執行此命令,我的應用程序將掛起,直到命令完成運行。
如何從Perl腳本異步運行Bash命令?
我必須運行Bash命令。但是這個命令需要幾分鐘才能運行。從Perl腳本異步執行Bash命令
如果我正常(同步)執行此命令,我的應用程序將掛起,直到命令完成運行。
如何從Perl腳本異步運行Bash命令?
您可以使用threads
異步開始猛砸,
use threads;
my $t = async {
return scalar `.. long running command ..`;
};
後來手動測試,如果線程準備加入,並在非阻塞的方式得到輸出,
my $output = $t->is_joinable() && $t->join();
如果您不關心結果,您可以使用system("my_bash_script &");
。它會立即返回,腳本完成需要完成的任務。
我有兩個文件:
$ cat wait.sh
#!/usr/bin/bash
for i in {1..5}; { echo "wait#$i"; sleep 1;}
$cat wait.pl
#!/usr/bin/perl
use strict; use warnings;
my $t = time;
system("./wait.sh");
my $t1 = time;
print $t1 - $t, "\n";
system("./wait.sh &");
print time - $t1, "\n";
輸出:
wait#1
wait#2
wait#3
wait#4
wait#5
5
0
wait#1
wait#2
wait#3
wait#4
wait#5
可以看出,第二個電話會立即返回,但它一直寫到標準輸出。
如果您需要與孩子溝通,則需要使用fork
並重定向STDIN
和STDOUT
(和STDERR
)。或者您可以使用IPC::Open2或IPC::Open3包。無論如何,在呼叫者退出之前等待孩子退出總是一個好習慣。
如果你想等待執行的過程中,你可以嘗試使用Bash是這樣的:
#!/usr/bin/bash
cpid=()
for exe in script1 script2 script3; do
$exe&
cpid[$!]="$exe";
done
while [ ${#cpid[*]} -gt 0 ]; do
for i in ${!cpid[*]}; do
[ ! -d /proc/$i ] && echo UNSET $i && unset cpid[$i]
done
echo DO SOMETHING HERE; sleep 2
done
這個腳本起初異步啓動腳本#並存儲在陣列中的PID被稱爲cpid
。然後是一個循環;它瀏覽它們仍在運行(/ proc/exists)。如果不存在,則顯示文本UNSET <PID>
,並從陣列中刪除PID。
它不是防彈的,就好像DO SOMETHING HERE
零件運行時間很長,那麼相同的PID可以被添加到另一個過程中。但它在平均環境中效果很好。
但這種風險也可降低:
#!/usr/bin/bash
# Enable job control and handle SIGCHLD
set -m
remove() {
for i in ${!cpid[*]}; do
[ ! -d /proc/$i ] && echo UNSET $i && unset cpid[$i] && break
done
}
trap "remove" SIGCHLD
#Start background processes
cpid=()
for exe in "script1 arg1" "script2 arg2" "script3 arg3" ; do
$exe&
cpid[$!]=$exe;
done
#Non-blocking wait for background processes to stop
while [ ${#cpid[*]} -gt 0 ]; do
echo DO SOMETHING; sleep 2
done
該版本允許腳本時的異步子進程退出接收SIGCHLD信號。如果收到SIGCHLD,它會異步查找第一個不存在的進程。等待while循環減少了很多。
另一個選項是'open(my $ fh,'| - ','wait.sh',...)'或'open(my $ fh,' - ','wait.sh',... )'如果你想讀取它的輸出或寫入它的輸入,但不是兩者。 – reinierpost
不,你不瞭解我@TrueY,我的bash命令需要很多時間才能運行,所以我希望當bash命令執行時,我的應用程序顯示文本「正在執行...」,並在完成命令後,系統triiger(通知)我的應用程序顯示「執行完成!」。 –
@ThếAnhNguyễn:對不起,我的誤解,但你的描述不包含太多的信息。我有一個[所以回答其他問題](http://stackoverflow.com/questions/16772186/bash-parallelize-md5sum-checksum-on-many-files/16773505#16773505)。它在bash中運行特定數量的並行程序。我根據您的需求定製它。 – TrueY
正常這樣做的方式是fork
。您將獲得腳本分支,然後子代會在Bash腳本上調用exec
或system
(取決於孩子是否需要處理Bash腳本的返回代碼,或者與其交互)。
然後,您的父母可能需要wait
和/或SIGCHILD
處理程序的組合。
如何處理它的確切細節取決於您的情況和確切的需求。
請參閱[我如何在Perl中觸發並忘記進程?](http://stackoverflow.com/questions/2133910/how-can-i-fire-and-forget-a-process-in-perl) – devnull
你關心bash輸出嗎? –
是的。我想要結果,什麼和什麼時候?像這樣:當命令完成時,它會提醒我的應用程序,如事件觸發器。 –