2012-02-23 126 views
6

我試圖創建一個shell腳本,在我的Mac上獲取Skype應用程序的進程ID如何從進程名稱獲取進程ID?

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

以上工作正常,但有兩個問題:

1)的grep命令會得到所有的過程,如果他們的名字只包含 「Skype的」。我如何確保它只能得到結果,如果進程名稱正好是Skype

2) 我想使從該一個外殼腳本,其可以從終端但過程名中使用應該是這個腳本的參數:

#!/bin/sh 

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

這不是返回任何東西我認爲這是因爲awk中的$ 2也被視爲一個參數。我該如何解決這個問題?

回答

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 

而且,您可以通過簡單地使用awk爲您選擇線路的功能來消除head。在awkNR是你的記錄號碼。因此,你可以這樣做:

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

如果pgrep在Mac上可用,則可以使用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' 從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 
1

可以格式化PS的使用-o [場]輸出,...和列表通過使用-C [COMMAND_NAME]進程名;然而,PS仍將打印列標題,其可以通過穿過的grep -v管道它PID

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

除去其中$ 1人的命令名(在這種情況下的Skype)

1

方法1 - 使用AWK

我看不出有任何理由使用-l標誌(長格式),我也看不出有任何理由使用grep和awk在同一時間:AWK具有內置的grep功能。這是我的計劃:用ps輸出僅有2列:PID和命令,然後用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 
}