从Perl脚本异步执行Bash命令

从Perl脚本异步执行Bash命令,perl,bash,asynchronous,Perl,Bash,Asynchronous,我必须运行Bash命令。但是这个命令需要几分钟才能运行 如果我正常(同步)执行此命令,我的应用程序将挂起,直到命令完成运行 如何从Perl脚本异步运行Bash命令?如果您不关心结果,可以使用系统(“my\u Bash\u script&”)。它将立即返回,脚本执行需要执行的操作 我有两个文件: $ cat wait.sh #!/usr/bin/bash for i in {1..5}; { echo "wait#$i"; sleep 1;} $cat wait.pl #!/usr/bin/pe

我必须运行Bash命令。但是这个命令需要几分钟才能运行

如果我正常(同步)执行此命令,我的应用程序将挂起,直到命令完成运行


如何从Perl脚本异步运行Bash命令?

如果您不关心结果,可以使用
系统(“my\u Bash\u 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
可以看出,第二个调用立即返回,但它一直在向stdout写入

如果您需要与孩子沟通,则需要使用
fork
和重定向
STDIN
STDOUT
(和
STDERR
)。或者您可以使用或包。无论如何,在调用者退出之前等待孩子退出总是一个好的做法

如果要等待已执行的进程,可以在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可以添加到另一个进程中。但它在一般环境下运行良好

但这种风险也可以降低:

#!/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循环大大减少。

您可以使用
线程来异步启动Bash

use threads;
my $t = async {
  return scalar `.. long running command ..`;
};
然后手动测试线程是否准备好加入,并以非阻塞方式获得输出

my $output = $t->is_joinable() && $t->join();

通常的方法是使用
fork
。您将拥有脚本分叉,然后子脚本将调用Bash脚本上的
exec
system
(取决于子脚本是否需要处理Bash脚本的返回代码,或者是否与之交互)

然后,您的父母可能希望组合使用
wait
和/或
SIGCHILD
处理程序


如何处理它的具体细节在很大程度上取决于您的情况和具体需求。

请参阅您是否关心bash输出?是的。我想要结果,什么时候?类似于:当命令完成时,它会像事件触发器一样向我的应用程序发出警报。下面是获取脚本输出的线程示例,但有时必须手动检查脚本是否已完成。+1。我有个小问题。如果在使用
async
$t
之后,perl返回一个错误:
全局符号“$t”需要显式的包名
。A
sleep 1$t
之前,code>解决了这个问题,但是有没有合适的方法来处理这个问题?
my$t=async{return`./wait.sh`;}
print$t。如果在这两行之间添加了
sleep 1
,那么它可以正常工作。我已经使用活动线程退出了
Perl:
,您不需要
sleep
来避免这种行为,就像
my$foo=$t->join()一样将阻止,直到线程准备好加入。Hmmm<代码>$t->加入也不工作,因为
$t
不可见(相同的错误消息)。在
cygwin
CentOS 5.7
@TrueY下也一样,如果您想读取其输出或写入其输入,另一个选项是
open(my$fh,“|-”,“wait.sh”,…)
open(my$fh,“-”,“wait.sh”,…)
。你不了解我@TrueY,我的bash命令需要很多时间才能运行,所以我希望在bash命令执行时,我的应用程序显示文本“正在执行…”,在完成命令后,系统triiger(注意)我的应用程序显示“执行完成!”。@Thế安古伊ễ对不起,我误解了,但是你的描述没有包含太多的信息。我吃了一顿饭。它在bash中运行特定数量的并行程序。我为你量身定做。