如何在Mac OS X上使用进程名称在Bash脚本中检查进程是否正在运行?
我正在尝试编写一个Bash脚本,如果进程已停止,则重新启动进程,但如果进程仍在运行,则不执行任何操作。
解析这个:
ps aux | grep -v grep | grep -c [-i] $ProcessName
...这可能是你最好的选择。
ps aux
列出了所有当前正在运行的进程,包括被 grep -v grep
所过滤掉的 Bash 脚本自身,该方法由 Jacob(在评论中)提出,并且 grep -c [-i] $ProcessName
返回一个可选的、不区分大小写的整数,表示该进程名称的进程数量,Sebastian 建议使用整数返回。
这是一个简短的脚本,它可以实现你所需的功能:
#!/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
将解决这个问题。
-gt 1
而不是 0
,因为 Bash 脚本中的 grep
命令本身也会被计算为 ps aux
中的行之一,至少在我的初步测试中是这样的。 - Chris Redfordwc
前的管道中添加一个 grep -v grep
。这样,grep
命令就会被排除在找到的匹配数之外。 - Jacobgrep
来维护-gt 0
功能。例如:ps aux | grep -i $ProcessName | grep -v grep | wc -l
。 - morgantnum=$(ps ax | grep -c -i "[Tt]ransmission")
。 - Sebastian Stumpfpgrep
(参见@Nick Zalutskiy的答案)有任何优势? - Matthemattics一个更短的解决方案:
if pgrep $PROCESS_NAME; then
echo 'Running';
fi
说明:
pgrep
命令如果存在匹配 $PROCESS_NAME
的进程则退出代码为 0,否则退出代码为 1。
if
语句检查 pgrep
的退出代码,对于退出代码来说,0 表示成功。
-x
选项,因为默认情况下它匹配子字符串。使用-x
选项可以改变这种行为,使其需要进程名称的精确匹配。 - Auke另一种方法是使用(滥用?)killall
命令的-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安装程序的脚本中提取了这个技巧。
pidof
,而不是Linux。在Mac OS X上,-d
选项由man killall
文档记录。除非有一些事实或法定标准化,否则不同操作系统上具有相同名称的程序之间可能没有太多共性。 - Jonathan Lefflerps axo pid,command | grep "[S]kype"
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"
echo "iTunes pid: $(ps axo pid,command | grep "[i]Tunes.app" | awk '{print $1}')"
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
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
我没有足够的声誉来评论上面的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
当然有!
OpenBSD和Darwin(Mac OS X)的pgrep、pkill和pfind。
http://proctools.sourceforge.net
(也可通过 MacPorts 获取:port info proctools)
pidof 由 nightproductions.net 开发
#!/bin/sh
ps axc |awk "BEGIN{ n=tolower(\"$1\")}\
tolower(\$5) ~n {print \$1}";
只需创建名为“pidof”的脚本,并使用此内容将其放入您的路径中,即在其中一个目录中。
echo $PATH
chmod 755 /usr/local/bin/pidof
kill -9 `pidof pyth`
也许对于原帖已经太晚了,但这可能会帮助其他发现这个线程的人。
上面提到的amrox主题的以下修改在我的OS X上重新启动应用程序效果很好:
killall -d TextEdit &> /dev/null && killall TextEdit &> /dev/null; open -a TextEdit
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位于同一目录中。
Mac 有 pidof 命令吗?...
if pidof $processname >/dev/null ; then echo $processname is running ; fi
launchd
,这是苹果替代了cron
,init
,inetd
等工具。它有许多选项可以在各种上下文和时间启动和重新启动进程。请参阅man launchd
,man launchd.plist
,并在 Google 上查找各种文档和教程。 - Ned Deilylaunchd
。 - Chris Redford