【问题标题】:Check if Mac process is running using Bash by process name通过进程名称检查 Mac 进程是否正在使用 Bash 运行
【发布时间】:2010-12-21 18:27:06
【问题描述】:

如何使用 Bash 脚本中的进程名称检查 Mac OS X 上的进程是否正在运行?

我正在尝试编写一个 Bash 脚本,如果进程停止,它将重新启动它,但如果它仍在运行,则什么也不做。

【问题讨论】:

  • 我正在将“unix”添加到标签列表中,因为这个问题实际上并没有特定于 mac 的内容......(留下“mac”,所以特定于 mac 的人也会找到它......)
  • 顺便说一句,如果你在 OS X 上创建一个类似守护进程的进程,你应该看看launchd,Apple 替代了croninitinetd 等。它有许多选项可以在各种上下文和时间启动和重新启动进程。有关各种文档和教程,请参阅 man launchdman launchd.plist 和 google。
  • 谢谢内德。我实际上使用 Lingon 作为launchd 的用户友好界面。
  • 布赖恩,你错了一半。 Mac OS X 是基于 BSD 的,并且在涉及到这一点的许多命令中具有略微不同的语义。不过,并不是说我认为 Linux 标记不合适。
  • 我必须在同一个系统(构建系统)中为 Mac OS X、OpenBSD、各种 Linux'es、AIX、Solaris 和 Cygwin 解决这个问题。最终使用带有临时文件和进程监控的两阶段锁定变得更容易,而不仅仅是进程监控(例如单独的“ps”)。不过,这并不是您问题的真正答案,但请考虑它是一般性建议。最大的麻烦之一是(尤其是在 Mac OS X 中)ps 参数会随着操作系统的不同版本而变化。

标签: macos bash unix process


【解决方案1】:

解析这个:

ps aux | grep -v grep | grep -c [-i] $ProcessName

...可能是你最好的选择。

ps aux 列出了所有当前正在运行的进程,包括 Bash 脚本本身,该脚本本身由 grep -v grep 根据 Jacob 的建议(在 cmets 中)解析出来,grep -c [-i] $ProcessName 返回可选的不区分大小写的整数进程数并返回整数由塞巴斯蒂安建议。

这是一个简短的脚本,可以满足您的需求:

#!/bin/bash
PROCESS=myapp
number=$(ps aux | grep -v grep | grep -ci $PROCESS)

if [ $number -gt 0 ]
    then
        echo Running;
fi

编辑:我最初在grep 中包含了一个-i 标志,以使其不区分大小写;我这样做是因为我尝试的示例程序是 python,它在 Mac OS X 上以 Python 运行——如果您完全了解应用程序的情况,则不需要 -i

这种方法的优势在于它可以随您扩展 - 将来,如果您需要确保应用程序的 五个 实例正在运行,那么您已经开始计算了。唯一需要注意的是,如果另一个应用程序在其命令行中包含您的程序名称,它可能会出现——grep 的正则表达式将解决该问题,如果您很狡猾(并遇到此问题)。

研究 psgrepwc 的 Darwin 手册页。

【讨论】:

  • 谢谢。这有一个例外:它必须是-gt 1 而不是0,因为来自Bash 脚本本身的grep 命令被算作ps aux 中的行之一,至少在我的初步测试中是这样。
  • 我喜欢在wc 之前将grep -v grep 添加到管道中。这样,grep 命令就会从找到的匹配数中排除。
  • 它是否适用于非常长的文件名和路径?特别是如果它们一开始就相似?例如。 my-long-filename-that-is-really-stupid-of-file-1, my-long-filename-that-is-really-stupid-of-file-2... 我敢打赌它不会,在至少不是在 Linux 和 Mac OS X 上,使用相同的参数 ps...
  • Jed 和 Chris,您可以使用另一个否定的 grep 来表示 'grep' 以维持 -gt 0 的功能。例如:ps aux | grep -i $ProcessName | grep -v grep | wc -l.
  • 您不必链接这么多命令。 grep 提供您需要的一切:num=$(ps ax | grep -c -i "[Tt]ransmission")
【解决方案2】:

更短的解决方案:

if pgrep $PROCESS_NAME; then
    echo 'Running';
fi

解释:

pgrep 如果有与$PROCESS_NAME 匹配的进程正在运行,则以0 退出,否则以1 存在。
if 检查pgrep 的退出代码,并且就退出代码而言, 0 表示成功。

【讨论】:

  • 你可能想使用-x,因为默认情况下它匹配子字符串。 -x 改变了这种行为,因此它要求进程名称完全匹配。
  • @Hypermattt 这不是公认的答案,因为他是在我问这个问题 4 年后写的。不过,很酷的解决方案。绝对有我的投票。
  • 不幸的是,如果您在包装器中运行某些东西(例如 python),则无法正常工作。 Jed Smith 的解决方案可能会更好地发挥作用
【解决方案3】:

另一种方法是使用(滥用?)-d 命令的-d 选项。 -d 选项实际上不会终止进程,而是打印将要执行的操作。如果找到匹配的进程,它也会以0 状态退出,如果没有,它也会以1 状态退出。把这些放在一起:

#!/bin/bash
`/usr/bin/killall -d "$1" &> /dev/null`
let "RUNNING = ! $?"     # this simply does a boolean 'not' on the return code
echo $RUNNING

为了给予应有的荣誉,我最初从 iTunes 安装程序的脚本中提取了这项技术。

【讨论】:

  • EWW。我不会使用-1,因为我认为这应该只用于不正确或不适当的答案,但是哇。当您可以使用 ps 和 grep 时,为什么要这样做?特别是因为我很确定使用 ps 和 grep 正是 killall 所做的......
  • 其实 killall 比 'ps | 聪明一点grep'。如果你只是 grep ps 的输出,你可能会得到误报。做作,但说你的过程被命名为“图书馆”。 'ps waux | grep Library' 将匹配 Mac 上的很多东西。 killall 方法虽然我承认有点古怪,但只会匹配名为“库”的实际进程。
  • 很抱歉,您使用的是什么系统?我在 killall 命令中没有看到 -d 选项。 linux.die.net/man/1/killall
  • @sobi3ch:讨论是关于 Mac OS X 上没有 pidof,而不是 Linux。 -d 选项在 Mac OS X 上由 man killall 记录。在不同操作系统上的同名程序之间不一定有太多共同点,除非有一些标准化——事实上或法律上。
【解决方案4】:

这个简单的命令就可以解决问题。进程名称周围的方括号可防止 grep 命令显示在进程列表中。注意逗号后面没有空格。可能存在一些可移植性问题,因为某些 unix 系统上的 ps 可能需要在选项前加上破折号:

ps axo pid,command | grep "[S]kype"

优点是您可以在 if 语句中使用结果,如下所示:'

if [[ ! $(ps axo pid,command | grep "[i]Tunes.app") ]]; then
    open -a iTunes
fi

或者如果你更喜欢这种风格:

[[ ! $(ps axo pid,command | grep "[S]kype") ]] && open -a Skype  || echo "Skype is up"

另一个优点是您可以通过向 awk '{print $1}' 添加管道来获取 pid。

echo "iTunes pid: $(ps axo pid,command | grep "[i]Tunes.app" | awk '{print $1}')"

【讨论】:

    【解决方案5】:

    您可以使用 killall 或 kill,具体取决于您是尝试按 PID 还是按名称查找任务。

    按名称:

    if ! killall -s -0 $PROCESS_NAME >/dev/null 2>&1; then
      # Restart failed app, or do whatever you need to prepare for starting the app.
    else
      at -f $0 +30seconds # If you don't have this on cron, you can use /usr/bin/at
    fi
    

    按 PID:

    if ! kill -0 $PID 2>/dev/null; then
      # Restart app, do the needful.
    else
      at -f $0 +30seconds
    fi
    

    如果您查看OSX 手册,您会看到一组不同的进程管理命令;因为它不是 linux 内核,所以它们会以不同的方式管理进程是有道理的。

    https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/killall.1.html

    我的终端的示例输出(当然删除了用户名和主机名):

    user@localhost:~$ kill -0 782 # This was my old, stale SSH Agent.
    bash: kill: (782) - No such process
    user@localhost:~$ echo $?
    1
    
    user@localhost:~$ kill -0 813 # This is my new SSH agent, I only just created.
    user@localhost:~$ echo $?
    0
    

    kill -0 的返回码总是会以一种安全的方式来检查进程是否正在运行,因为 -0 不会发送任何将由应用程序处理的信号。它不会杀死应用程序,而“kill”仅称为“kill”,因为它通常用于停止应用程序。

    当您查看它在源代码中使用的接口时,您会发现它实际上是直接与进程表交互(而不是从 ps 获取潜在加载的输出),并且只是向应用程序发送信号。一些信号指示应用程序应该关闭或停止,而其他信号则告诉它重新启动服务,或重新读取配置,或重新打开文件描述符以记录最近轮换的文件。 "kill" 和 "killall" 可以做的很多事情都不会终止应用程序,并且经常使用它来简单地向应用程序发送信号。

    【讨论】:

      【解决方案6】:

      我缺乏对上述 killall 答案发表评论的声誉,但 killall -s 在没有发送任何信号的情况下这样做:

      killall -s "$PROCESSNAME" &> /dev/null
      if [ $? -eq 0 ]; then
          echo "$PROCESSNAME is running"
          # if you also need the PID:
          PID=`killall -s "$PROCESSNAME" | awk '{print $3}'`
          echo "it's PID is $PID"
      fi
      

      【讨论】:

        【解决方案7】:

        我已经扩展了一个在网上找到的 pidof 脚本以使用正则表达式(通常是子字符串)并且不区分大小写

        #!/bin/sh
        ps axc  |awk "BEGIN{ n=tolower(\"$1\")}\
            tolower(\$5) ~n {print  \$1}";
        

        只需使用此内容创建一个名为“pidof”的脚本,并将其放在您的路径中,即在其中一个目录中

        echo $PATH
        

        并使其可执行(可能使用 sudo)

        chmod 755 /usr/local/bin/pidof
        

        当然是这样使用它

        kill -9 `pidof pyth`
        

        【讨论】:

          【解决方案8】:

          Mac 有 pidof 吗? ...

          if pidof $processname >/dev/null ; then echo $processname is running ; fi
          

          【讨论】:

            【解决方案9】:

            肯定有!

            用于 OpenBSD 和 Darwin (Mac OS X) 的 pgrep、pkill 和 pfind

            http://proctools.sourceforge.net

            (也可以通过 MacPorts 获得:port info proctools)

            由 nightproductions.net 提供的 pidof

            【讨论】:

            • 很棒的东西,但不是标准的。有时最好只使用标准的东西来解决这个问题,有时不是!
            【解决方案10】:

            对于 OP 来说可能为时已晚,但这可能会帮助其他找到此线程的人。

            上述 amrox 主题的以下修改适用于在我的 OS X 上重新启动应用程序:

            killall -d TextEdit &> /dev/null && killall TextEdit &> /dev/null; open -a TextEdit
            

            我使用以下 AppleScript 来更新和重启守护进程:

            tell application "System Events" to set pwd to POSIX path of container of (path to me)
            do shell script "launchctl unload -w /Library/LaunchDaemons/time-test.plist; cp -f " & quoted form of pwd & "/time-test.plist /Library/LaunchDaemons; launchctl load -w /Library/LaunchDaemons/time-test.plist" with administrator privileges
            

            假定原始或更新的 plist 文件与 AppleScript 位于同一目录中。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-03-06
              • 1970-01-01
              • 2015-05-28
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多