Linux / Unix命令以确定进程是否正在运行?


97

我需要一个独立于平台的(Linux / Unix | OSX)shell / bash命令,该命令将确定特定进程是否正在运行。例如mysqldhttpd...最简单的方法/命令是什么?

Answers:


168

虽然pidofpgrep是确定正在运行的工具,但遗憾的是,它们在某些操作系统上均不可用。绝对的故障保护将使用以下内容:ps cax | grep command

Gentoo Linux上的输出:

14484?S 0:00 apache2
14667吗?S 0:00 apache2
19620?SL 0:00 apache2
21132?SS 0:04 apache2

OS X上的输出:

42582 ?? Z 0:00.00(smbclient)
46529 ?? Z 0:00.00(smbclient)
46539 ?? Z 0:00.00(smbclient)
46547 ?? Z 0:00.00(smbclient)
46586 ?? Z 0:00.00(smbclient)
46594 ?? Z 0:00.00(smbclient)

在Linux和OS X上,grep都会返回退出代码,因此很容易检查是否找到了该进程:

#!/bin/bash
ps cax | grep httpd > /dev/null
if [ $? -eq 0 ]; then
  echo "Process is running."
else
  echo "Process is not running."
fi

此外,如果您想要PID的列表,也可以轻松地对这些ID进行grep:

ps cax | grep httpd | grep -o'^ [] * [0-9] *'

在Linux和OS X上谁的输出是相同的:

3519 3521 3523 3524

以下内容的输出为空字符串,从而使该方法对于未运行的进程而言是安全的:

回声 ps cax | grep aasdfasdf | grep -o '^[ ]*[0-9]*'

这种方法适用于编写简单的空字符串测试,然后甚至遍历发现的PID。

#!/bin/bash
PROCESS=$1
PIDS=`ps cax | grep $PROCESS | grep -o '^[ ]*[0-9]*'`
if [ -z "$PIDS" ]; then
  echo "Process not running." 1>&2
  exit 1
else
  for PID in $PIDS; do
    echo $PID
  done
fi

您可以通过将其保存到具有执行权限(chmod + x running)的文件(名为“ running”)并使用参数执行该文件来对其进行测试: ./running "httpd"

#!/bin/bash
ps cax | grep httpd
if [ $? -eq 0 ]; then
  echo "Process is running."
else
  echo "Process is not running."
fi

警告!!!

请记住,您只是在解析输出,ps ax这意味着从Linux输出中可以看出,它不仅与进程匹配,而且还传递给该程序的参数。我强烈建议在使用此方法时尽可能具体(例如./running "mysql"也将匹配“ mysqld”进程)。我强烈建议which在可能的情况下使用来检查完整路径。


参考文献:

http://linux.about.com/od/commands/l/blcmdl1_ps.htm

http://linux.about.com/od/commands/l/blcmdl1_grep.htm


该进程可以运行,但已停止。因此,如果目标是测试mysqld或httpd是否“启动并正在运行”(响应),则还应检查它是否已停止。
oluc

2
抱歉,但是从语义的角度来看答案肯定是正确的,但我完全反对尝试通过对过程arg向量进行模式匹配来查找过程。任何这样的方法注定迟早都会失败(您实际上是在承认自己,只是说需要进行更多检查)。我在一个单独的答案中添加了我自己的推荐。
peterh 2013年

6
grep也将发现自己运行(例如ps cax | grep randomname将始终返回0,因为grep出土文物grep randomname(希望这是明确的...)一个解决方法是添加周围的进程名的第一个字母,例如方括号。ps cax | grep [r]andomname
凯尔G.

ps cax | rev | cut -f1 -d' ' | rev将仅显示名称列,以便于解析。
Tyzoid 2015年

1
ps cax可能不会完全输出命令名称。例如,它打印“铬浏览器”而不是“铬浏览器”。
jarno 2015年

24

您应该知道PID!

通过尝试对流程参数(例如pgrep "mysqld")进行某种模式识别来查找流程是一种注定迟早会失败的策略。如果您有两个mysqld正在运行怎么办?忘记这种方法。您可以暂时正确使用它,并且可以工作一两年,但是随后发生了一些您未曾想到的事情。

只有进程ID(pid)才是真正唯一的。

在后台启动某些东西时,请始终存储该pid。在Bash中,可以使用$!Bash变量来完成。这样可以为您省下很多麻烦。

如何确定进程是否正在运行(通过pid)

所以现在的问题变成了如何知道pid是否正在运行。

只需做:

ps -o pid = -p <pid>

这是POSIX,因此可移植。如果进程正在运行,它将返回pid本身;如果进程未运行,则将不返回任何值。严格来说,该命令将返回单个列,pid但由于我们给出了一个空的标题标头(等号前面的内容),并且这是所请求的唯一列,因此ps命令将根本不使用标头。这就是我们想要的,因为它使解析更加容易。

这将适用于Linux,BSD,Solaris等。

另一种策略是测试以上ps命令的退出值。如果进程正在运行,则应为零;如果未运行,则应为非零。POSIX规范指出,ps如果发生错误,则必须退出> 0,但我不清楚什么构成“错误”。因此,尽管我非常确定它可以在所有Unix / Linux平台上正常工作,但我个人并没有使用该策略。


1
除非这不能回答确定服务是否正在运行的问题。该PID将不会在这样的情况下是已知的,因此,如果你这个答案是唯一有效的知道PID。
生命高速公路

2
错误。我的全部评论意见是退后一步,说如果您首先发现自己必须采取某种形式grep <sometext>来找到给定的流程,那么在启动该流程时,您做错了什么,恕我直言。我从OP的问题中得出的结论是,他确实控制了流程的启动方式。
peterh

2
对于OP问题的更正确的“术语”应该是“跨平台命令来确定服务是否正在运行”,它不是运行检查的同一系统,而是外部系统,因此PID不会众所周知。
生命高速公路

2
这不是万无一失的。您感兴趣的进程可能已经死了,直到系统运行了足够长的时间以使PID可以回绕,然后又为另一个进程分配了您要检查的相同PID。 stackoverflow.com/questions/11323410/linux-pid-recycling
claymation

1
@claymation。有道理。但是,PID方法仍然比在过程args上进行模式匹配更好,因为PID冲突比说意外启动同一服务的两个实例要少得多。只是我的两分钱。:-)
peterh '16

15

在大多数Linux发行版中,您可以使用pidof(8)。

它将打印指定进程的所有正在运行实例的进程ID,如果没有实例在运行,则不打印任何内容。

例如,在我的系统上(我有四个实例,bash一个remmina正在运行):

$ pidof bash remmina
6148 6147 6144 5603 21598

在其它UNIX系统中,pgrep或组合ps,并grep会取得同样的事情,正如其他人理所当然地指出。


+1 pidof httpd在Red Hat 5上工作正常。但是在我的Red Hat 4 pidof上却不存在:-(
olibre 2012年

确实,此命令没有我想像的那么广泛,因此我编辑了答案以使其更清楚。
弗雷德里克·哈米迪

确实干净的答案。(在受支持的系统上)。谢谢。
Mtl Dev

7

这应该适用于大多数Unix,BSD和Linux版本:

PATH=/usr/ucb:${PATH} ps aux | grep httpd | grep -v grep

经过测试:

  • SunOS 5.10 [因此PATH=...]
  • Linux 2.6.32(CentOS)
  • Linux 3.0.0(Ubuntu)
  • 达尔文11.2.0
  • FreeBSD 9.0-稳定
  • 红帽企业版Linux ES版本4
  • 红帽企业Linux服务器版本5

2
+1是ps。为了避免第二个,grep我建议:ps aux | grep [h]ttpd
olibre 2012年

我在这里没有使用方括号把戏来简化将变量放入main的过程grep
Johnsyweb

1
好吧;)我刚刚在Red Hat AS 4和Red Hat AP 5上进行了测试。因此,您可以在列表中添加:Red Hat Enterprise Linux ES版本4Red Hat Enterprise Linux Server版本5。干杯
olibre 2012年

@Downvoter:为什么?我错过了什么?据我所知,可接受的答案是进行相同的查找!
Johnsyweb

6

最简单的方法是使用ps和grep:

command="httpd"
running=`ps ax | grep -v grep | grep $command | wc -l`
if [ running -gt 0 ]; then
    echo "Command is running"
else
    echo "Command is not running"
fi

如果您的命令包含一些命令参数,那么您也可以在'grep $ command'之后放置更多的'grep cmd_arg1',以过滤掉您不感兴趣的其他可能进程。

示例:告诉我是否有带有提供的参数的java进程:

-Djava.util.logging.config.file = logging.properties

在跑

ps ax | grep -v grep | grep java | grep java.util.logging.config.file=logging.properties | wc -l

2
实际上,使用ps cax消除了使用的需要grep -v。因此,例如,您可以使用:ps cax | grep java > /dev/null || echo "Java not running"
生命高速公路

1
第三行有错误。请将“ running”更改为“ $ running”。
程序员

5

只是一个小小的补充:如果您将-c标志添加到ps,则无需grep -v随后删除包含grep进程的行。即

ps acux | grep cron

是在bsd-ish系统(包括MacOSX)上需要的所有输入内容-u,如果您需要的信息较少,可以省去一切。

在本机ps命令遗传指向SysV的系统上,您将使用

ps -e |grep cron

要么

ps -el |grep cron 

对于包含不仅仅是pid和进程名称的列表。当然,您可以使用-o <field,field,...>选项选择要打印的特定字段。


这个答案如何携带?(您说ps命令的不同形式应在不同平台上使用)
peterh 2013年

不幸的是,ps是其中一个工具,根据其祖先,它们具有不同的选项集来实现相同的结果。因此,除非您围绕此内容编写自己的(同样与其他任何内容都不兼容的)包装器,否则方法将是了解遗产的主要内容并做出相应调整。编写脚本时有所不同-在这里,您将使用这些差异来确定所处的分支并适应脚本的行为。底线:您需要同时了解两者。著名的例子:Larry Wall的“配置”脚本。著名语录:恭喜,您未使用Eunice。
Tatjana Heuser

5

综合各种建议,我能想到的最简洁的版本(没有不可靠的grep会触发单词的一部分)是:

kill -0 $(pidof mysql) 2> /dev/null || echo "Mysql ain't runnin' message/actions"

kill -0不会杀死进程,但会检查进程是否存在,然后返回true,如果您的系统上没有pidof,请在启动进程时存储pid:

$ mysql &
$ echo $! > pid_stored

然后在脚本中:

kill -0 $(cat pid_stored) 2> /dev/null || echo "Mysql ain't runnin' message/actions"

3

我使用pgrep -l httpd但不确定在任何平台上都存在...
谁可以在OSX上进行确认?


谢谢@Johnsyweb。您还可以检查pidof一下吗?好,你做到了。谢谢。因此,我们应该在OSX上找到其他工作方式……您的基本方法ps|grep可能是单一解决方案;-)
olibre 2012年

1

您应该知道过程的PID。

启动它时,其PID将记录在$!变量中。将此PID保存到文件中。

然后,您将需要检查此PID是否对应于正在运行的进程。这是一个完整的框架脚本:

FILE="/tmp/myapp.pid"

if [ -f $FILE ];
then
   PID=$(cat $FILE)
else
   PID=1
fi

ps -o pid= -p $PID
if [ $? -eq 0 ]; then
  echo "Process already running."  
else
  echo "Starting process."
  run_my_app &
  echo $! > $FILE
fi

基于该回答peterh。知道给定PID是否正在运行的诀窍在ps -o pid= -p $PID指令中。


0

如果命令“ ps”,“ pidof”和rest不可用,则可以使用此方法。我个人经常在我的工具/脚本/程序中使用procfs。

   egrep -m1  "mysqld$|httpd$" /proc/[0-9]*/status | cut -d'/' -f3

很少解释发生了什么:

  1. -m1-在第一次比赛时停止进程
  2. “ mysqld $ | httpd $”-grep将匹配以mysqld或httpd结尾的行
  3. / proc / [0-9] *-bash将匹配以任何数字开头的行
  4. 剪切-只需用定界符'/'分割输出并提取字段3

0

这将打印基本名称为“ chromium-browser”的进程数:

ps -e -o args= | awk 'BEGIN{c=0}{
 if(!match($1,/^\[.*\]$/)){sub(".*/","",$1)} # Do not strip process names enclosed by square brackets.
 if($1==cmd){c++}
}END{print c}' cmd="chromium-browser"

如果显示“ 0”,则表明该进程未运行。该命令假定进程路径不包含空格。我尚未使用暂停进程或僵尸进程对此进行测试。

在Linux上gwak用作awk替代测试。

这是一个更加通用的解决方案,并带有一些示例用法:

#!/bin/sh
isProcessRunning() {
if [ "${1-}" = "-q" ]; then
 local quiet=1;
 shift
else
 local quiet=0;
fi
ps -e -o pid,args= | awk 'BEGIN{status=1}{
 name=$2
 if(name !~ /^\[.*\]$/){sub(".*/","",name)} # strip dirname, if process name is not enclosed by square brackets.
 if(name==cmd){status=0; if(q){exit}else{print $0}}
}END{exit status}' cmd="$1" q=$quiet
}

process='chromium-browser'

printf "Process \"${process}\" is "
if isProcessRunning -q "$process" 
 then printf "running.\n"
 else printf "not running.\n"; fi

printf "Listing of matching processes (PID and process name with command line arguments):\n"
isProcessRunning "$process"

0

这是我的版本。特征:

  • 检查确切的程序名称(函数的第一个参数)。搜索“ mysql”将与运行“ mysqld”不匹配
  • 搜索程序参数(函数的第二个参数)

脚本:

#!/bin/bash

# $1 - cmd
# $2 - args
# return: 0 - no error, running; 1 - error, not running
function isRunning() {
    for i in $(pidof $1); do
        cat /proc/$i/cmdline | tr '\000' ' ' | grep -F -e "$2" 1>&2> /dev/null
        if [ $? -eq 0 ]; then
            return 0
        fi
    done
    return 1
}

isRunning java "-Djava.util.logging.config.file=logging.properties"
if [ $? -ne 0 ]; then
    echo "not running, starting..."
fi

0

没有一个答案对我有用,所以这是我的:

process="$(pidof YOURPROCESSHERE|tr -d '\n')"
if [[ -z "${process// }" ]]; then
  echo "Process is not running."
else
  echo "Process is running."
fi

说明:

|tr -d '\n'

这将删除由终端创建的回车。其余的可以通过这篇文章解释。


-1

以下仅基于POSIX标准命令和选项的shell函数应在大多数(如果没有)Unix和linux系统上运行。:

isPidRunning() {
  cmd=`
    PATH=\`getconf PATH\` export PATH
    ps -e -o pid= -o comm= |
      awk '$2 ~ "^.*/'"$1"'$" || $2 ~ "^'"$1"'$" {print $1,$2}'
  `
  [ -n "$cmd" ] &&
    printf "%s is running\n%s\n\n" "$1" "$cmd" ||
    printf "%s is not running\n\n" $1
  [ -n "$cmd" ]
}

$ isPidRunning httpd
httpd is running
586 /usr/apache/bin/httpd
588 /usr/apache/bin/httpd

$ isPidRunning ksh
ksh is running
5230 ksh

$ isPidRunning bash
bash is not running

请注意,当传递可疑的“ 0]”命令名称时,它将阻塞,并且也将无法识别名称中包含空格的进程。

还要注意,最受支持和接受的解决方案需要非便携式ps选项,并且无偿使用了一个外壳,尽管它很受欢迎,但并不能保证每个Unix / Linux机器上都存在该外壳(bash


$ isPidRunning 0]打印,例如“ 0”正在运行3 [ksoftirqd / 0] 8 [rcuop / 0] 17 [rcuos / 0] 26 [rcuob / 0] 34 [migration / 0] 35 [watchdog / 0]”。
jarno 2015年

您需要该PATH做什么用?
jarno 2015年

我在这里进一步开发了解决方案。
jarno 2015年

@jarno PATH设置是脚本可移植的要求。否则,它将至少在Solaris 10和更早版本以及可能的其他Unix实现上失败。
jlliagre 2015年

1
@jarno我可能会这样做,但也需要为awk重复此PATH设置。请注意,我已还原到旧的backtick语法,以便可以使用POSIX之前的语法bourne shell移植。
jlliagre 2015年
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.