我正在尝试创建一个外壳脚本,在我的Mac上获取Skype应用程序的进程ID。
ps -clx | grep'Skype'| awk'{print $ 2}'|头-1
上面的方法工作正常,但是有两个问题:
1)如果grep名称仅包含“ Skype”,则将获得所有进程。如果进程名称恰好是Skype,我如何确保仅得到结果?
2)我想从中制作一个shell脚本,可以在终端上使用它,但是进程名应该是该脚本的参数:
#!/bin/sh
ps -clx | grep '$1' | awk '{print $2}' | head -1
这不返回任何东西。我认为这是因为awk中的$ 2也被视为一个参数。我该如何解决?
您的ps -cl1
输出看起来像这样:
UID PID PPID F CPU PRI NI SZ RSS WCHAN S ADDR TTY TIME CMD
501 185 172 104 0 31 0 2453272 1728 - S ffffff80145c5ec0 ?? 0:00.00 httpd
501 303 1 80004004 0 31 0 2456440 1656 - Ss ffffff8015131300 ?? 0:11.78 launchd
501 307 303 4004 0 33 0 2453456 7640 - S ffffff8015130a80 ?? 0:46.17 distnoted
501 323 303 40004004 0 33 0 2480640 9156 - S ffffff80145c4dc0 ?? 0:03.29 UserEventAgent
因此,每行的最后一个条目是您的命令。这意味着您可以使用正则表达式的全部功能来帮助您。
$
在正则表达式中表示字符串的结尾,因此,您可以使用$
指定输出不仅必须包含Skype
,而且还必须以Skype
结尾。这意味着如果您有一个名为Skype Controller
的命令,则不会将其上拉:
ps -clx | grep 'Skype$' | awk '{print $2}' | head -1
您还可以通过使用ps -o
格式来简化所需的列来简化操作:
ps -eo pid,comm | grep 'Skype$' | awk '{print $1}' | head -1
并且,您可以通过简单地使用head
为您选择线路的功能来消除awk
。在awk
中,NR
是您的记录号。因此,您可以这样做:
ps -eo pid,comm | grep 'Skype$' | awk 'NR == 1 {print $1}'
哎呀,现在我想到了,我们也可以消除grep
:
ps -eo pid,comm | awk '/Skype$/ {print $1; exit}'
这是使用awk使用正则表达式的能力。如果该行包含正则表达式'Skype $',它将打印第一列,然后退出
唯一的问题是,如果您有命令Foo Skype
,它也会将其拾取。要消除这种情况,您必须做一些花哨的步法:
ps -eo pid,comm | while read pid command
do
if [[ "$command" = "Skype" ]]
then
echo $pid
break
fi
done
while read
正在读取两个变量。诀窍是read
使用空格分隔读取的变量。但是,由于只有两个变量,最后一个变量将包含整行的其余部分。因此,如果命令是Skype Controller,则即使其中有空格,整个命令也会放入$command
。
现在,我们不必使用正则表达式。我们可以将命令与等号进行比较。
此输入时间更长,但实际上您使用的命令更少,管道也更少。记住awk
在每一行中循环。您在这里所做的只是使其更加明确。最后,这实际上比您最初拥有的效率要高得多。
如果pgrep
在Mac上可用,则可以使用pgrep '^Skype$'
。这将列出所有名为Skype
的进程的进程ID。
第二个示例的问题是$ 1用单引号引起来,这防止bash扩展变量。已经有一个无需手动解析ps输出即可完成所需功能的实用程序。
您可以在AppleScript中执行此操作:
您可以使用-o [field]来格式化ps的输出,...,并使用-C [command_name]来按进程名称列出;但是,ps仍将打印列标题,可以通过将其通过管道传递来删除grep -v PID
我会这样:
使用双引号允许bash执行变量替换。单引号禁用bash变量替换机制。
pgrep myAwesomeAppName