如何检查从Bash循环完成卷曲PID

时间:2015-11-28 08:54:15

标签: bash curl background-process

我无法弄清楚我在OSX上的错误。当我尝试查看Curl何时完成时,该过程仍然被加载。我从未见过CURL FINISHED消息。

#!/bin/bash

curl -S -o example.com http://example.com/downloads/example.zip &
CURL_PID=$!
echo -e "CURL PID = $CURL_PID"
while :
do
    sleep 1
    if [ -n $(ps -p$CURL_PID -o pid=) ]; then
        echo "CURL NOT FINISHED"
    else
      echo "CURL FINISHED"
      break
    fi
done

运行此操作时请注意OSX的Bash版本:

#!/bin/bash

PIDX=1
if [ -n $(ps -p$PIDX -o pid=) ]; then
  echo "PROCESS 1 IS THERE"
else
  echo "PROCESS 1 IS NOT THERE"
fi

......它说过程1就在那里。 (每个人都有一个PID 1,所以这只是一个例子。)所以,我知道我的if陈述是正确的。 if行不需要双引号。

请注意,我不能在$CURL_PID上使用等待,因为您在此处看不到的是我也在使用OSX的osascript命令来显示一个对话框,显示“正在下载... “,它上面还有一个取消按钮和它自己的$DLG_PID,所以我无休止地循环,直到他们取消对话(意味着$DLG_PID点消失)或$CURL_PID是消失(意味着下载终于完成了,所以我现在可以运行kill $DLG_PID。)

在OSX上,请注意我在curl语句之前也这样做。

osascript -e 'tell app "System Events" to display dialog "Downloading..." with title "My App Installer" buttons {"Cancel"}' &

因此,如果有人取消了对话框,我会通过PID终止curl并退出无限循环(并退出bash脚本)。如果他们没有取消该对话框,并且curl结束,那么我通过PID终止对话框并退出bash脚本。

2 个答案:

答案 0 :(得分:3)

通常你会使用wait

curl http://... &
do_something
wait
echo "CURL has finished"

答案 1 :(得分:2)

轮询后台作业的便携方式是使用kill内置,并发送信号0以查看它是否可以交付。 kill -0 $pid(其中$pid是子进程的PID)如果子进程仍在运行,则返回零,如果已经死,则返回非零值。请注意,对于子进程,这是安全且安全(来自PID回收)(而不是某些随机进程在其他地方启动,PID写入PID文件),原因如here所示:

  

每个UNIX进程也有一个父进程。此父进程是启动它的进程,但如果父进程在新进程之前结束,则可以更改为init进程。 (也就是说,init将获取孤立进程。)了解这种父/子关系至关重要,因为它是UNIX中可靠进程管理的关键。在进程死亡之后,进程的PID将永远不会被释放使用。在父进程等待PID查看它是否结束并检索其退出代码时。如果父级结束,则该过程将返回到init,后者会为您执行此操作。

     

这一点很重要,原因如下:如果父进程管理其子进程,则可以绝对肯定,即使子进程终止,也没有其他新进程可以意外地回收子进程的PID,直到父进程有等待那个PID并注意到孩子死了。这使父进程能够保证它对子进程的PID总是指向该子进程,无论它是活着的还是“僵尸”。没有其他人有这种保证。

当然,较新版本的OS X不使用init(取而代之的是launchd),但原理是相同的。

顺便说一句,整个页面值得一读:http://mywiki.wooledge.org/ProcessManagement

鉴于此,这里有一个示例脚本可以执行您想要的操作(它需要一个URL参数 - 要下载的URL)。如果有些事情不清楚,我就会烦恼。

#!/usr/bin/env bash
osascript -e 'tell app "System Events" to display dialog "Downloading..." with title "Downloader" buttons {"Cancel"}' &>/dev/null &
dialog_pid=$!
curl -sSLO "$1" &
curl_pid=$!
timer=0
while kill -0 "$curl_pid" &>/dev/null; do
    kill -0 "$dialog_pid" &>/dev/null || { echo "User cancelled download from dialog."; kill "$curl_pid" &>/dev/null; exit 1; }
    sleep 1
    (( timer++ ))
    echo "Been downloading for $timer seconds..."
done
echo "Finished."
kill "$dialog_pid" &>/dev/null
wait &>/dev/null

运行它:

> ./download https://github.com/torvalds/linux/archive/v4.4-rc2.tar.gz
Been downloading for 1 seconds...
Been downloading for 2 seconds...
<omitted>
Been downloading for 38 seconds...
Finished.

中途取消:

> ./download https://github.com/torvalds/linux/archive/v4.4-rc2.tar.gz
Been downloading for 1 seconds...
Been downloading for 2 seconds...
Been downloading for 3 seconds...
User cancelled download from dialog.

丑陋的是杀死osascript作业的PID并不会忽略对话框......我无法解决这个问题,因为我绝对害怕AppleScript。