我正在尝试创建一个shell脚本,在我的Mac上获取Skype应用的进程ID 。
ps -clx | grep'Skype'| awk'{print $ 2}'|头-1 -
以上工作正常,但有两个问题:
1) 如果他们的名字只包含“Skype”,那么 grep 命令将获得所有进程。如果流程名称正好是 Skype ,我如何确保只获得结果?
2) 我想从这里创建一个shell脚本,可以从终端使用,但进程名称应该是这个脚本的参数:
#!/bin/sh
ps -clx | grep '$1' | awk '{print $2}' | head -1
这不会返回任何东西。我认为这是因为awk中的 $ 2 也被视为参数。我该如何解决这个问题?
答案 0 :(得分:14)
您的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控制器,则整个命令将被放入$command
,即使其中有空格。
现在,我们不必使用正则表达式。我们可以将命令与相等进行比较。
输入时间较长,但实际上使用的命令较少,管道较少。请记住awk
循环遍历每一行。你在这里所做的只是让它更明确。最后,这实际上比你原来拥有的效率更高。
答案 1 :(得分:1)
如果Mac上有pgrep
,则可以使用pgrep '^Skype$'
。这将列出名为Skype
的所有进程的进程ID。
您在脚本中使用了错误的引号:
ps -clx | grep "$1" | awk '{print $2}' | head -1
或
pgrep "^$1$"
答案 2 :(得分:1)
第二个例子的问题是$ 1是单引号,这可以防止bash扩展变量。已有一个实用程序可以在不手动解析ps输出的情况下完成您想要的任务。
pgrep "$1"
答案 3 :(得分:1)
我会这样:
ps aux | grep Skype | awk 'NR==1 {print $2}'
====更新====
使用不带引号的参数,并使用awk
#!/bin/bash
ps aux | grep $1 | awk 'NR==1 {print $2}'
答案 4 :(得分:1)
您可以在AppleScript中执行此操作:
tell application "System Events"
set skypeProcess to the process "Skype"
set pid to the unix id of skypeProcess
pid
end tell
这意味着您可以使用'osascript'从shell脚本中获取PID:
$ osascript -e "tell application \"System Events\"" -e "set skypeProcess to the process \"Skype\"" -e "set pid to the unix id of skypeProcess" -e "pid" -e "end tell"
3873
答案 5 :(得分:1)
您可以使用-o [field],...格式化ps的输出,并使用-C [command_name]按进程名称列出;但是,ps仍然会打印列标题,可以通过管道删除它通过grep -v PID
ps -o pid -C "$1" |grep -v PID
其中$ 1将是命令名称(在本例中为Skype)
答案 6 :(得分:1)
我没有看到任何使用-l标志(长格式)的理由,我也没有看到任何理由同时使用grep和awk:awk内置了grep功能。这是我的计划:使用ps并输出2列:pid和command,然后使用awk选择你想要的内容:
ps -cx -o pid,command | awk '$2 == "Skype" { print $1 }'
这种方法的优点是,如果你已经在bash中编写脚本,你甚至不需要awk,它可以保存一个进程。解决方案比其他方法更长,但非常直接。
#!/bin/bash
ps -cx -o pid,command | {
while read pid command
do
if [ "_$command" = "_$1" ]
then
# Do something with the pid
echo Found: pid=$pid, command=$command
break
fi
done
}
答案 7 :(得分:0)
使用双引号允许bash执行变量替换。 单引号禁用bash变量替换机制。
ps -clx | grep "$1" | awk "{print $2}" | head -1
答案 8 :(得分:0)
pgrep myAwesomeAppName
这在Catalina 10.15.2下非常有效