Базовое имя или заканчивается в awk? - PullRequest
3 голосов
/ 24 февраля 2012

Я использую awk, чтобы получить pid определенного процесса по имени.

#!/bin/sh

for pid in $(ps | awk '$4 == "foo" { print $1 }')
do
    i=1
    echo "killing foo at pid $pid"
    kill $pid && echo 'ok' || echo 'failed'
done

, где ps вывод на OSX выглядит примерно так:

$ ps
  PID TTY           TIME CMD
 1858 ttys000    0:00.15 -bash
 4148 ttys000    0:01.37 /a/b/c/foo

, но мой сценарий оболочки работает, только если процесс в столбце CMD точно равен foo (без абсолютных путей).

Я думаю, что могу использовать basename, но как я могу назвать это с awk?
ИЛИ
Есть ли что-то вроде $4.endswith('foo') в awk?

Ответы [ 6 ]

7 голосов
/ 24 февраля 2012

awk можно использовать регулярные выражения. Поэтому вместо $4 == "foo" вы можете сделать что-то вроде:

awk '$4 ~ /\/foo$/ { print $1 }'

Регулярное выражение находится между / и /. \/foo$ говорит "обратный слеш, за которым следует foo, а затем конец поля". В этом случае ваше поле равно /a/b/c/foo, поэтому оно будет соответствовать.

3 голосов
/ 24 февраля 2012

Прежде всего, вы должны использовать while read конструкцию вместо for.С циклом for необходимо дождаться выполнения команды в $(...), прежде чем цикл for может начаться.Кроме того, вы могли бы переполнить буфер команд.Сегодня это не главная проблема, но когда вы столкнетесь с этим, вы никогда не получите никаких признаков того, что что-то пошло не так:

ps | awk '$4 == "foo" { print $1 }' | while read pid
do
    i=1
    echo "killing foo at pid $pid"
    kill $pid && echo 'ok' || echo 'failed'
done

Ничего общего с вашей проблемой, но мне нужно избавиться от неекомод.


Теперь перейдем к вашему ответу:

awk автоматически делает цикл, поэтому, так как вы все равно используете awk, почему бы не позволить ему выполнить работудля тебя?В большинстве реализаций awk есть команда system, поэтому вы можете выполнить kill прямо внутри скрипта awk.

Кроме того, взгляните на man ps и проверьте параметры PS.Большинство команд ps принимают опцию -o, которая позволяет вам указать, какие поля печатать.Моя команда ps (которая, как правило, используется в OS X) позволяет вам использовать ucomm, которая является просто именем команды без каталога или параметров командной строки.Звучит полезно для вашей ситуации.Я буду использовать ps -opid, ucomm, который будет печатать только два столбца для команды ps: PID и имя команды без параметров каталога и командной строки:

$ ps -o pid,ucomm
  PID UCOMM
    1 launchd         
   10 kextd           
   11 UserEventAgent  
   12 mDNSResponder   
   13 opendirectoryd  
   14 notifyd         
   15 fseventsd       
   16 configd         
   17 diskarbitrationd
   18 syslogd         

(выглядит только одно предупреждениекак ucomm обрезает все в 14-м или 16-м столбце. Просто, чтобы вы знали).

Для awk мы можем использовать параметр -v, чтобы определить переменную Awk.Это полезно, если вы пишете сценарий оболочки и хотите, чтобы awk взял имя программы из параметров команды.

В Awk, как вы знаете, $ 1 будет представлять PID, а $ 2 будет представлять командубез параметров каталога или командной строки.

Мы можем использовать $2 == command, чтобы отфильтровать все строки в вашей команде ps, где команда foo.Это сокращение от оператора if.

И большинство реализаций awk имеют функцию system, которую можно использовать для запуска таких команд, как kill, изнутри вашего скрипта awk.Похоже, что у нас есть почти все, что нам нужно:

ps -o pid,ucomm | awk -v command="foo" '$2 == command {system("kill " $1)}'

Это хорошая чистая строка, но она не проверяет состояние системной команды и не выводит эхо при сбое или какой команде иПИД ты убиваешь.

Хорошо, что Awk - не просто заумная команда.Это также заумный язык программирования.Мы могли бы проверить возвращение команды system и добавить несколько операторов печати.Я не проверял это, но это должно быть довольно близко:

ps -o pid,ucomm | awk -v command="foo" '$2 == command {
   print "Killing " $2 " at PID " $1
   if (system("kill " $1)) {
       print "Failed to kill PID " $1
   }
}'

Возможно, вместо if будет if (! system("kill " $1)) {.

3 голосов
/ 24 февраля 2012

В дополнение к регулярным выражениям вы можете использовать строковые манипуляции как substr($4, length($4) - 2) == "foo".

2 голосов
/ 24 февраля 2012

Кажется, вы пытаетесь уничтожить все процессы с именем 'foo', как насчет:

killall foo
2 голосов
/ 24 февраля 2012

Для условия вы можете использовать

$4 ~ /\/foo$/

, что означает «4-е поле соответствует косой черте (с экранированием), за которой следует« foo »в конце строки».

0 голосов
/ 22 февраля 2014

При поиске pids вы должны исключить процесс awk, иначе он может прервать процесс поиска.

kill $(ps -aef | awk -v program="mplayer" '$0 ~ program {if ($0 !~ "awk") print $2}')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...