2012-02-23 5 views
6

Я пытаюсь создать сценарий оболочки, получая код id приложения Skype на моем Mac.Как получить идентификатор процесса из имени процесса?

ps-clx | grep 'Skype' | awk '{print $ 2}' | голова -1

выше работает нормально, но есть две проблемы:

1) Grep команда будет получить весь процесс, если их название содержит только "Skype". Как я могу гарантировать, что он получит только результат, если имя процесса точно соответствует Skype?

2) Я хотел бы сделать скрипт из этого, который может быть использован с терминала, но имя процесса должно быть аргументом этого сценария:

#!/bin/sh 

ps -clx | grep '$1' | awk '{print $2}' | head -1 

Это не возвращая что-нибудь. Я думаю, это связано с тем, что $ 2 в awk также рассматривается как аргумент. Как я могу это решить?

ответ

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 Controller, вся команда будет помещена в $command, хотя в ней есть пробел.

Теперь нам не нужно использовать регулярное выражение. Мы можем сравнить команду с равенством.

Это длиннее для ввода, но на самом деле вы используете меньше команд и меньше труб. Помните, что awk перебирает каждую линию. Все, что вы здесь делаете, делает его более явным. В конце концов, это на самом деле намного эффективнее того, что вы изначально имели.

1

Если на Mac имеется pgrep, вы можете использовать pgrep '^Skype$'. В этом списке будет указан идентификатор процесса для всех процессов, называемых Skype.

Вы использовали неправильные кавычки в сценарии:

ps -clx | grep "$1" | awk '{print $2}' | head -1 

или

pgrep "^$1$" 
1

Проблемы с вторым примером является то, что $ 1 в одинарных кавычках, что предотвращает Баш от расширения переменного , Уже есть утилита, которая выполняет то, что вы хотите, без ручного анализа вывода ps.

pgrep "$1" 
0

Используйте двойные кавычки, чтобы позволить bash выполнять подстановку переменных. Одиночные кавычки отключить механизм замены переменных bash.

ps -clx | grep "$1" | awk "{print $2}" | head -1 
1

Я бы так что-то вроде:

ps aux | grep Skype | awk 'NR==1 {print $2}' 

==== ==== UPDATE

Используйте параметр без кавычек и использовать одинарные кавычки для awk

#!/bin/bash 
ps aux | grep $1 | awk 'NR==1 {print $2}' 
1

Вы можете сделать это в AppleScript:

tell application "System Events" 
    set skypeProcess to the process "Skype" 
    set pid to the unix id of skypeProcess 
    pid 
end tell 

означает, что вы можете использовать «osascript», чтобы получить 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 
1

Вы можете форматировать вывод пс с помощью -o [поле], ...и список по имени процесса с использованием -C [имя_команда], однако, пс все равно будет печатать заголовок столбца, который может быть удален по конвейеру через ГРЭП -v ПИД

ps -o pid -C "$1" |grep -v PID 

где $ 1 будет именем команды (в этот случай Skype)

1

Метод 1 - Использование AWK

Я не вижу никаких причин, чтобы использовать флаг -l (длинный формат), я не вижу никаких причин, чтобы использовать Grep и AWK в то же время: AWK имеет встроенную функцию grep.Вот мой план: использовать пс и выход только 2 колонки: PID и команду, а затем использовать AWK, чтобы выбрать то, что вы хотите:

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

Метод 2 - Использование баш

Этот метод имеет то преимущество, что если вы уже используете скрипт в 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 
} 
Смежные вопросы