Как получить идентификатор процесса из имени процесса?
Я пытаюсь создать сценарий оболочки, получая идентификатор процесса приложения Skype на моем Mac.
ps-clx / grep 'Skype' / awk '{print $2} ' / head -1
выше работает нормально, но есть две проблемы:
1) The grep команда получит весь процесс, если их имя просто содержит "Skype". Как я могу гарантировать, что он получит только результат, если имя процесса точно Skype?
2) Я хотел бы сделать сценарий оболочки из этого, который можно использовать из терминала, но имя процесса должно быть аргументом этого скрипта:
#!/bin/sh
ps -clx | grep '' | awk '{print }' | head -1
Это ничего не возвращает. Я думаю, это потому, что $2 в awk также рассматривается как аргумент. Как я могу это решить?
8 ответов
код 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 }' | head -1
вы также можете упростить вещи, используя чтобы просто подтянуть столбцы, которые вы хотите:
ps -eo pid,comm | grep 'Skype$' | awk '{print }' | head -1
и, вы можете устранить head
С помощью awk
возможность выбора вашей линии для вас. В awk
, NR
- это рекордное количество. Таким образом, вы могли бы сделать это:
ps -eo pid,comm | grep 'Skype$' | awk 'NR == 1 {print }'
черт, теперь, когда я думаю об этом, мы могли бы устранить grep
тоже:
ps -eo pid,comm | awk '/Skype$/ {print ; 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
хотя в нем есть место.
теперь нам не нужно использовать регулярное выражение. Мы можем сравнить команду с равенством.
это больше для вида, но на самом деле вы используете меньше команд и меньше трубопроводов. Помни!--14--> проходит через каждую строку. Все, что вы здесь делаете, это делаете это более явным. В конце, это на самом деле гораздо более эффективно, чем то, что у вас изначально было.
если pgrep
доступно на Mac, вы можете использовать pgrep '^Skype$'
. В этом списке будет указан идентификатор процесса всех процессов с именем Skype
.
вы использовали неправильные кавычки в своем скрипте:
ps -clx | grep "" | awk '{print }' | head -1
или
pgrep "^$"
проблема со вторым примером заключается в том, что $1 находится в одинарных кавычках, что предотвращает расширение переменной bash. Уже есть утилита, которая выполняет то, что вы хотите, без ручного анализа вывода ps.
pgrep ""
Вы можете сделать это в 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
вы можете отформатировать вывод ps, используя-o [поле],... и список по имени процесса с помощью -C [command_name]; однако ps все равно напечатает заголовок столбца, который можно удалить, пропустив его через grep-v pid
ps -o pid -C "" |grep -v PID
где $1 будет именем команды (в данном случае Skype)
Я бы так что-то вроде:
ps aux | grep Skype | awk 'NR==1 {print }'
= = = = = UPDATE ====
использовать параметр без кавычек и используйте одинарные кавычки для awk
#!/bin/bash
ps aux | grep | awk 'NR==1 {print }'
метод 1-Используйте awk
Я не вижу причин использовать флаг-l (длинный формат), я также не вижу причин использовать grep и awk одновременно: awk имеет встроенную возможность grep. Вот мой план: используйте ps и выводите только 2 столбца: pid и command, затем используйте awk, чтобы выбрать то, что вы хотите:
ps -cx -o pid,command | awk ' == "Skype" { print }'
Метод 2-Используйте bash
этот метод имеет то преимущество, что если вы уже скрипт в bash, вам даже не нужен awk, который сохраняет один процесс. Этот решение длиннее, чем другой метод, но очень прямолинейно.
#!/bin/bash
ps -cx -o pid,command | {
while read pid command
do
if [ "_$command" = "_" ]
then
# Do something with the pid
echo Found: pid=$pid, command=$command
break
fi
done
}
используйте двойные кавычки, чтобы позволить bash выполнять подстановку переменных. Одинарные кавычки отключают механизм подстановки переменных bash.
ps -clx | grep "" | awk "{print }" | head -1