在Shell脚本中,我如何(1)在后台启动命令(2)等待x秒(3)在该命令运行时运行第二个命令?


11

这是我需要发生的事情:

  1. 在后台启动进程A
  2. 等待x秒
  3. 在前台启动进程B

如何使等待发生?

我看到“睡眠”似乎停止了所有操作,实际上我不想“等待”过程A完全完成。我已经看到了一些基于时间的循环,但是我想知道是否还有更清洁的方法。


4
我建议您通过提供一个简单的示例说明您已经尝试过的方法,以增强此问题。
安迪·道尔顿

10
您从哪里得到sleep停止进程A 的印象?您可以显示您正在使用的测试过程,还是可以输出指示呢?如果过程-A 停止,它更可能是它试图在后台运行,并得到制止出于这个原因,而不是涉及到什么,而从终端读取sleep
Charles Duffy

3
...如果这样,process_a </dev/null &将其stdin附加到/dev/nullTTY而不是TTY,这可能足以避免该问题。
Charles Duffy

根据我的经验,睡眠只会阻止当前进程,因此不会阻止以前使用&在后台启动的进程
MADforFUNandHappy

Answers:


28

除非我对您的问题有误解,否则可以使用以下简短脚本轻松实现:

#!/bin/bash

process_a &
sleep x
process_b

wait如果希望脚本process_a在退出前等待完成,请在末尾添加一个额外的字符)。

您甚至可以单行执行此操作,而无需脚本(如@BaardKopperud所建议):

process_a & sleep x ; process_b

6
请注意,您不需要这样做bash,任何shell都可以使用,包括您系统的sh,因此您无需为脚本添加对bash的依赖关系。
斯特凡Chazelas

4
或者简单地:process_a&sleep x; process_b
Baard Kopperud

9

您可以使用后台控制运算符(&)在后台运行进程,并使用sleep命令在运行第二个进程之前等待,即:

#!/usr/bin/env bash
# script.sh

command1 &
sleep x
command2

这是两个命令的示例,这些命令可以打印出一些带时间戳的消息:

#!/usr/bin/env bash

# Execute a process in the background
echo "$(date) - Running first process in the background..."
for i in {1..1000}; do
    echo "$(date) - I am running in the background";
    sleep 1;
done &> background-process-output.txt &

# Wait for 5 seconds
echo "$(date) - Sleeping..."
sleep 5 

# Execute a second process in the foreground
echo "$(date) - Running second process in the foreground..."
for i in {1..1000}; do
    echo "$(date) - I am running in the foreground";
    sleep 1;
done

运行它以验证它表现出所需的行为:

user@host:~$ bash script.sh

Fri Dec  1 13:41:10 CST 2017 - Running first process in the background...
Fri Dec  1 13:41:10 CST 2017 - Sleeping...
Fri Dec  1 13:41:15 CST 2017 - Running second process in the foreground...
Fri Dec  1 13:41:15 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:16 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:17 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:18 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:19 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:20 CST 2017 - I am running in the foreground
...
...
...

2
问题要求“在前台启动进程B ”。
Sparhawk

1
@Sparhawk哇。完全误读了-没有解释。感谢您的注意-代码已更正。顺带一提,您的用户名怀有深深的怀念。
igal

1
别担心!(而且用户名最初是对此章的引用,但后来我才意识到它是Eddings角色!而且让我想重新阅读那些书……)
Sparhawk

5

我喜欢@ dr01的答案,但他不检查退出代码,因此您不知道自己是否成功。

这是一个检查退出代码的解决方案。

#!/bin/bash

# run processes
process_a &
PID1=$!
sleep x
process_b &
PID2=$!
exitcode=0

# check the exitcode for process A
wait $PID1    
if (($? != 0)); then
    echo "ERROR: process_a exited with non-zero exitcode" >&2
    exitcode=$((exitcode+1))
fi

# check the exitcode for process B
wait $PID2
if (($? != 0)); then
    echo "ERROR: process_b exited with non-zero exitcode" >&2
    exitcode=$((exitcode+1))
fi
exit ${exitcode}

通常我将PID存储在bash数组中,然后pid检查是for循环。


2
您可能要反映你的脚本一样的退出状态的退出码A & sleep x; B; ret=$?; wait "$!" || exit "$ret"
斯特凡Chazelas

1
@StéphaneChazelas好主意。我更新了代码,以确保如果一个或两个均失败,则返回非零退出码。
特雷弗·博伊德·史密斯

OP希望process_b在前台运行。大概process_a可以在process_b运行时退出,但是您仍然可以直接退出并以正常方式wait收集前台process_b的退出状态后获得退出状态$?
彼得·科德斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.