我正在使用终端模拟器运行 Ubuntu 16.04。
我有两个脚本:a.sh
和b.sh
。
a.sh
来电b.sh
。
a.sh
echo "a is running"
sleep 5s
bash b.sh
sleep 5s
echo "a is still running"
b.sh
echo "b is now running"
sleep 1000s
echo "Bananas"
有没有办法运行a.sh
,在完成之前停止b.sh
(在打印 Bananas 之前)并让a.sh
运行完成并打印“a is still running”?
我曾尝试放入pkill -f b.sh
其中a.sh
,但两者都a.sh
在完成b.sh
之前停止a.sh
。
答案1
在某一时刻,你似乎已经接近你想要的了。
a.sh
#!/bin/sh
echo "a.sh running"
sleep 10s
(sleep 10s; pkill -f b.sh) &
bash b.sh
sleep 10s
pkill -f b.sh
echo "a.sh still running"
b.sh
(与你的版本相同)
echo "b is now running"
sleep 1000s
echo "Bananas"
(sleep 10s; pkill -f b.sh) &
中的行创建a.sh
一个子 shell,该子 shell 休眠 10 秒,然后终止b.sh
。然后它将该子 shell 放入后台,以便a.sh
可以继续运行。
a.sh
然后运行b.sh
,运行sleep 1000s
。十秒后,sleep 10s
子 shell 中的 完成,并且它(子 shell)运行pkill -f b.sh
,杀死b.sh
进程。
a.sh
然后恢复运行。第二个pkill -f b.sh
不执行任何操作,因为该b.sh
进程已经终止。
这是它运行时发生的情况:
$ ./a.sh a.sh 运行 # 立即地 b 现在正在运行 # 上述之后大约10秒 ./a.sh: 第 6 行: 13684 终止 bash b.sh # 上述之后大约10秒 a.sh仍在运行 # 上述之后大约10秒 $ # 紧接在上面之后
这样做的好处是,如果很快完成a.sh
,可以立即恢复运行。b.sh
只有b.sh
运行超过 10 秒才会pkill
启动。在另一个答案中,即使已经结束,也必须在占用时间之前a.sh
闲置。sleep
pkill
b.sh
我明白了
./a.sh a.sh running b is now running Terminated
不是你报告的内容。任何想法?
一个月黑风高的夜晚。突然,一声枪响!
—这是一个漆黑的暴风雨之夜,史努比 作者:查尔斯·M·舒尔茨
pgrep
and 的参数pkill
是一个正则表达式;具体来说,是扩展正则表达式1。尝试cat
同时cut
运行2。然后执行pgrep c.t
- 它将列出两个 PID,您可以确认ps
它们是cat
和cut
。
如果你做了确切地正如我所说,你确实应该得到和我一样的结果。但我愿意打赌 42 Zorkmids,你做了一些不同的事情。你要么:
a.sh
以#!/bin/bash
she-bang(第一行)开头,而不是#!/bin/sh
, 或- 跑
a.sh
用bash a.sh
而不是./a.sh
.
突然,一声枪响!
b.sh
是一个正则表达式,匹配b
后跟任何字符,后跟sh
.它匹配自身 ( b.sh
),也匹配b!sh
、b~sh
、b&sh
、b7sh
和等内容bush
。还有……(等等)……也很配bash
!
因此pkill -f b.sh
会杀死所有 bash 进程,以及b.sh
名称中包含的任何其他进程。当我运行我运行的内容时,我的登录 shell(至少部分不受 bash 影响pkill
)是 bash,但a.sh
正在运行/bin/sh
(但b.sh
正在运行bash
)。该pkill -f b.sh
命令杀死了该bash b.sh
进程,因为它包含两个都 bash
和b.sh
。但/bin/sh
正在运行的a.sh
并没有受到影响。
假设你按照我相信的方式运行它(两种选择之一),
全部脚本进程正在运行bash
。所以pkill -f b.sh
命令杀死了全部脚本进程。
更改pkill -f b.sh
为pkill -f 'b\.sh'
(转义点,使其匹配仅有的一个点,而不是任何字符),您应该得到正确的结果。
________
1 pgrep(1)
2如果您有两个终端(shell 窗口),请cat | cut -f1
在其中一个终端中运行(使用来自终端的输入),并p
在另一个终端中运行 - 命令。如果您只有一个终端,请运行sleep 42 | cat | cut -f1 &
(如果没有sleep
,管道将立即崩溃),然后p
在同一窗口中运行 -commands 。
答案2
该行:
bash b.sh
将等待脚本完成,在结束b.sh
之前无法在脚本中执行任何操作,因为没有控制权。b.sh
a.sh
要让b.sh
脚本转到后台并将控制权交还给,a.sh
请使用类似于以下内容的命令:
bash b.sh &
这会立即返回控制权a.sh
,我们可以得到这样的脚本:
#!/bin/bash
echo "a is running"
sleep 1s
bash b.sh &
sleep 2
pkill -f 'b\.sh'
sleep 1s
echo "a is still running"
虽然脚本b.sh
仍然是:
#!/bin/bash
echo "b is now running"
sleep 1000s
echo "Bananas"
执行后你将得到:
$ ./a.sh
a is running
b is now running
./a.sh: line 7: 8424 Terminated bash b.sh
a is still running
为了避免出现“作业控制消息”,请使用子 shell,更改bash b.sh &
为:
(bash b.sh &)
并且,在执行时,您将得到:
$ ./a.sh
a is running
b is now running
a is still running
编辑:
您报告的“终止”响应的问题是您发布的 pkill 命令pkill -f b.sh
正在使用参数作为正则表达式。该正则表达式匹配b
后跟任何字符,.
后跟sh
.这与名称“bash”匹配,该程序也开始运行a.sh
,这解释了为什么a.sh
被终止。将 pkill 命令更改为:
pkill -f 'b\.sh'
确保匹配的正则表达式是纯字符串“b.sh”。
您可以通过放置以下内容来查看 pkill 将匹配的进程:
ps -f -o pid,cmd,args |grep 'b.sh'
就在 pkill 之前。
修改为,grep 'b\.sh'
发现实际上只匹配一个pid。
答案3
您的a.sh
脚本必须将b.sh
脚本作为后台作业运行,以便能够提前终止它。
由于b.sh
它作为后台作业运行,因此您可以访问其进程 ID (PID),这意味着您可以使用kill
它来发出信号。这比使用pkill
which 可能会向其他进程发出与您提供的模式匹配的信号更安全。
您可以在 中执行以下操作a.sh
:
#!/bin/sh
echo "A: I'm alive!"
./b.sh & bpid=$!
echo 'A: Sleeping for a short while'
sleep 2
echo 'A: Signalling B'
kill "$bpid"
echo "A: I'm done here"
将$!
扩展到最近启动的后台任务的 PID。
示例b.sh
:
#!/bin/sh
echo "B: I'm alive!"
echo 'B: Sleeping for longer than A does'
sleep 10
echo "B: I'm done here"
运行它:
$ ./a.sh
A: I'm alive!
A: Sleeping for a short while
B: I'm alive!
B: Sleeping for longer than A does
A: Signalling B
A: I'm done here
请注意,在调用完成之前,它b.sh
可能不会真正终止。这是、和的sleep
情况,但不是(with立即终止)。bash
dash
zsh
pdksh
ksh93
b.sh
答案4
我用过下面的方法。在 b.sh 中添加了一行,使其能够按要求工作
脚本 a.sh 将是相同的
script a.sh
echo "a is running"
sleep 5s
bash b.sh
sleep 5s
echo "a is still running"
=================================================== ===
script b.sh
echo "b is now running"
sleep 20s
exit
==>退出命令将从脚本中出来
echo "Bananas"
输出
a is running
b is now running
a is still running