如何从进程名称获取进程ID?

时间:2012-02-23 15:15:45

标签: macos bash awk grep

我正在尝试创建一个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 也被视为参数。我该如何解决这个问题?

9 个答案:

答案 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)

方法1 - 使用awk

我没有看到任何使用-l标志(长格式)的理由,我也没有看到任何理由同时使用grep和awk:awk内置了grep功能。这是我的计划:使用ps并输出2列:pid和command,然后使用awk选择你想要的内容:

ps -cx -o pid,command | awk '$2 == "Skype" { print $1 }'

方法2 - 使用bash

这种方法的优点是,如果你已经在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下非常有效