2012-02-24 48 views
3

我正在使用awk來按名稱獲取特定進程的pidbasename或endswith在awk中?

#!/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 

其中在OSX ps輸出是一樣的東西:

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

但我的shell腳本只有在CMD列的過程是完全foo(無絕對路徑)的作品。

我想我可以用basename,但我怎麼把它從awk

awk中有沒有類似$4.endswith('foo')的東西?

回答

6

awk可以使用正則表達式。因此,而不是$4 == "foo",你可以這樣做:

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

正則表達式是//之間。 \/foo$表示「反斜線後跟foo,然後是場的末尾」。在這種情況下,您的字段是/a/b/c/foo,所以它會匹配。

+0

謝謝!我精神振奮:) – user46874 2012-02-24 03:32:31

2

爲條件,你可以使用

$4 ~ /\/foo$/ 

轉換爲「第四場的(逃脫)斜槓隨後在該行的末尾‘富’相匹配。」

+0

謝謝!非常感謝 – user46874 2012-02-24 03:34:20

2

除了正則表達式,您還可以使用字符串操作substr($4, length($4) - 2) == "foo"

+0

啊,很高興知道。謝謝。 – user46874 2012-02-24 03:33:06

2

似乎你試圖殺死其中有名稱「富」的所有過程,怎麼樣:

killall foo 
+0

+1:我不知道存在的新命令。 t在我的Mac上寫了一個'pkill'腳本,因爲它沒有。我希望我知道之前的「killall」命令。 Mac上是否有等價的'pgrep'? – 2012-02-24 16:49:26

+0

@Hai Vu,非常好。我不知道這個命令。它適用於沉默殺死,但我也需要詳細殺死。謝謝。 – user46874 2012-02-24 17:24:57

+0

@ user46874:** killall -v **會做詳細的殺戮。 – 2012-02-24 18:59:25

3

首先,你應該使用一個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命令,因此您可以在awk腳本中執行kill

另外,看看man ps並檢查您的PS選項。大多數ps命令採用-o選項,該選項允許您指定要打印的字段。我的ps命令(恰好在OS X上)允許您使用ucomm,它只是沒有目錄或命令行參數的命令的名稱。聽起來對你的情況有用。我將使用ps -opid, ucomm這將只打印兩列的ps命令:PID,和命令名SANS目錄和命令行參數:

$ 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變量。如果您編寫shell腳本,並且希望awk從命令參數中獲取程序的名稱,這很有用。

在awk中,如你所知,$ 1將代表PID和$ 2將代表命令SAN的目錄或命令行參數。

我們可以使用$2 == command來篩選出您的ps命令中的所有行,其中命令爲foo。這是if聲明的快捷方式。

而且,大多數awk的實現都有system函數,可用於從awk腳本中運行諸如kill之類的命令。看起來我們有幾乎所有我們需要的一切:

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

這是一個乾淨的一個套,但它並不檢查系統命令的狀態,也不會迴應了,當它出現故障或有什麼命令和PID你正在殺害。

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)) {代替。

+0

Perl! Perl的最初設計目標,仍然是它的亮點,是作爲awk,sed,grep,find等許多複雜專用語言的單一通用替代品。諸如bash之類的shell腳本語言具有它們的甜蜜點但是他們傾向於使用awk和sed而不是替換它們。有些人現在喜歡用Python和Ruby來代替Perl。我一直在閱讀用於Unix和Linux系統管理的Python,但我不確定它可以真正替代Perl。 – minopret 2012-02-24 13:41:05

+0

@minopret - 我是一名Perl開發人員,是的,Perl可以做到這一點。但是,Perl不在標籤中,所以我在這種情況下儘量不要使用Perl解決方案。另外,Awk很簡單。我在我用Mac寫的Mac上有一個'pgrep'和'pkill'任務,因爲OS X沒有附帶這兩個命令。 – 2012-02-24 16:45:46

+0

@David W.,感謝您的洞察力。很有用! – user46874 2012-02-24 17:23:39

0

當尋找的PID,您必須排除awk的過程,否則會殺死搜索過程來代替。

kill $(ps -aef | awk -v program="mplayer" '$0 ~ program {if ($0 !~ "awk") print $2}')