在 KornShell 中检查 AIX 7.1.0 上正在运行的进程的正确且可靠的方法

在 KornShell 中检查 AIX 7.1.0 上正在运行的进程的正确且可靠的方法

我一直在尝试找到一种方法来检查脚本是否正在运行,因为我想确保在运行某些内容时没有任何其他实例。到目前为止,我已经尝试过:

#! /bin/ksh93

getProcessNum(){
    processNum=$(ps -ef | grep -E "$1" \
        | grep -vE "emacs|vi |ve |grep|ps|tail|tee|runProcess|jlast|tlast|elast" \
        | awk '/'$USER'/ { if($1 == "'$USER'") print $0}' \
        | awk -v myPid=$$ '{if ($3 != myPid) print $0}' \
        | wc -l
    )
}

getProcessNum "myAvoidedScript.k"

if [[ $processNum -gt 1 ]]; then
    echo "There are $processNum instances running. Stopping..."
else
    echo "You can continue"
fi

我得到了这个:

ThisProcessID=4063450
myUser  4063450  5636606   0 19:06:48 pts/10  0:00 /bin/ksh93 myAvoidedScript.k
myUser  8978492  5964234   0 19:06:48 pts/10  0:00 /bin/ksh93 myAvoidedScript.k
myUser  3277270  9109712 113 11:07:58  pts/5 70:50 /bin/ksh93 myAvoidedScript.k

我认为这种方式足以做到这一点,但有些进程即使属于同一脚本的一部分也会被计算在内。我注意到,当我尝试运行此脚本时,它返回一个大于 1 的数字,即使没有任何运行。

所以我说:也许如果我尝试消除在非常精确的时间开始的重复项就足够了,我尝试了这个:

#! /bin/ksh93

getProcessNum(){
    processNum=$(ps -ef | grep -E "$1" \
        | grep -vE "emacs|vi |ve |grep|ps|tail|tee|runProcess|jlast|tlast|elast" \
        | awk '/'$USER'/ { if($1 == "'$USER'") print $0}' \
        | awk -v myPid=$$ '{if ($3 != myPid) print $0}' \
        | sort -k 4 | awk '!x[$5]++' | wc -l
    )
}

getProcessNum "myAvoidedScript.k"
if [[ $processNum -gt 1 ]]; then
    echo "There are $processNum instances running. Stopping..."
else
    echo "You can continue"
fi

有时我得到正确的结果,但其他一些我得到这个

返回的 PID 并不总是与当前 PID ($$) 相同:

ThisProcessID=4063450
myUser  3177476  5964232   0 19:06:49 pts/10  0:00 /bin/ksh93 myAvoidedScript.k
myUser  3277270  9109712 113 11:07:58  pts/5 70:50 /bin/ksh93 myAvoidedScript.k

当您在接近一秒的时间运行此脚本时,它仍然会带来此完全相同脚本的两个实例。

ThisProcessID=4063450
myUser  4063450  5636606   0 19:07:48 pts/10  0:00 /bin/ksh93 myAvoidedScript.k
myUser  5177476  5964232   0 19:07:49 pts/10  0:00 /bin/ksh93 myAvoidedScript.k
myUser  3277270  9109712 113 11:07:58  pts/5 70:50 /bin/ksh93 myAvoidedScript.k

有谁知道如何确保无论我何时运行此脚本,它只会使正确的进程以可靠的方式运行?

附言。我知道我可以使用标志文件,但这意味着要更改很多脚本。

答案1

我没有 AIX 系统来测试这一点,但由于在执行ps.您可以尝试通过ps单独运行并将其输出捕获到临时文件或更简单的变量中来避免这种情况。您还可以将 grep、awk 和 wc 简化为一个 awk 命令。例如,

getProcessNum(){
    procs=$(ps -u "$USER" -f)
    processNum=$(printf '%s\n' "$procs" |
        awk -v myPid="$$" -v name="$1" '
            index($0,"ksh93 " name) != 0 && $2 != myPid {tot++}
            END {print tot}'
    )
}

答案2

有谁知道如何确保无论我何时运行此脚本,它只会使正确的进程以可靠的方式运行?

您可以要求ps列出当前用户拥有的进程-u $USER,并打印出它们的 pid、父 pid 和完整的命令字符串(命令和参数),然后将其传递给 awk 进行进一步检查。 Awk 被赋予当前脚本的 pid ( -v me=$1) 和要查找的进程名称 ( -v procname=$2),然后被告知查找符合三个要求的行:

  1. 其中 pid(第 1 列)是不是当前脚本的 pid,以及
  2. 其中 ppid(第 2 列)是不是当前脚本的 pid,以及
  3. 其中命令字符串与给定参数匹配

如果任何行满足所有这两个要求,那么 awk 将打印 pid;然后通过管道传输这些 pid(如果有)wc -l来计算它们的实例。您可以简单地增加一个计数器,但如果您想出于其他目的调查 pid,这将为您提供检索它们的方法。

getProcessNum() {
  ps -u "$USER" -o pid=,ppid=,args= |
  awk -v me="$1" -v procname="$2" \
    '$1 != me && $2 != me && index(substr($0,19,length(procname)), procname) { print $1 }' |
  wc -l
}

这一个的主要区别是嗯的是我要求ps打印父进程 pid,以便我们可以专门忽略当前脚本的任何子进程;另一个区别是,在确定与index.我这样做是为了尽可能防止误报,例如公认的人为的vi ksh93 myAvoidedScript.k.

您必须传递脚本的确切咒语(如 给出的那样)ps -o args,以便正确排除这些实例 - 例如此处的getProcessNum $$ "/bin/ksh93 myAvoidedScript.k"。如果可以使用参数 ( /bin/ksh93 myAvoidedScrip.k foo)、选项 ( ksh93 -x myAvoidedScript.k) 或完整路径 ( /bin/ksh93 /path/to/myAvoidedScript.k) 或使用不同的解释器路径 ( ./ksh93 myAvoidedScript.k) 或直接 ( ./myAvoidedScript.k) 调用脚本,则此检查将失败。

除非您可以保证精确的脚本调用,否则很难保证一次只执行该脚本的一个副本。

相关内容