2012-02-23 28 views
6

Tôi đang cố gắng tạo tập lệnh shell để lấy mã số quá trình của ứng dụng Skype trên máy Mac của mình.Làm cách nào để lấy id tiến trình từ tên quy trình?

ps -clx | grep 'Skype' | awk '{print $ 2}' | đầu -1

Trên đây là làm việc tốt, nhưng có hai vấn đề:

1) Các grep lệnh sẽ nhận được tất cả quá trình nếu tên của họ chỉ chứa "Skype". Làm thế nào tôi có thể đảm bảo rằng nó chỉ nhận được kết quả, nếu tên quy trình là chính xác Skype?

2) Tôi muốn thực hiện một kịch bản shell từ này, có thể được sử dụng từ nhà ga nhưng tên quá trình nên một cuộc tranh cãi kịch bản này:

#!/bin/sh 

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

Đây không phải là trả lại bất cứ điều gì. Tôi nghĩ rằng điều này là bởi vì các $ 2 trong awk được coi là một đối số quá. Làm sao tôi có thể giải quyết việc này?

Trả lời

14

đầu ra ps -cl1 của bạn trông như thế này:

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 

như vậy, mục cuối cùng trong mỗi dòng là lệnh của bạn. Điều đó có nghĩa là bạn có thể sử dụng toàn bộ sức mạnh của các cụm từ thông dụng để giúp bạn.

Các $ trong một biểu thức chính quy có nghĩa là sự kết thúc của chuỗi, do đó, bạn có thể sử dụng $ để xác định rằng không chỉ đầu ra phải có Skype trong nó, nó phải kết thúc với Skype. Điều này có nghĩa nếu bạn có một lệnh gọi Skype Controller, bạn sẽ không kéo nó lên:

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

Bạn cũng có thể đơn giản hóa mọi thứ bằng cách sử dụng định dạng ps -o để chỉ cần kéo lên cột mà bạn muốn:

ps -eo pid,comm | grep 'Skype$' | awk '{print $1}' | head -1 

Và, bạn có thể loại bỏ head chỉ đơn giản bằng cách sử dụng khả năng chọn dòng của bạn cho bạn. Trong số awk, NR là số hồ sơ của bạn. Vì vậy bạn có thể làm điều này:

ps -eo pid,comm | grep 'Skype$' | awk 'NR == 1 {print $1}' 

Heck, bây giờ mà tôi nghĩ về nó, chúng ta có thể loại bỏ các grep quá:

ps -eo pid,comm | awk '/Skype$/ {print $1; exit}' 

này đang sử dụng khả năng awk để sử dụng biểu thức thông thường. Nếu dòng chứa cụm từ thông dụng, 'Skype $', dòng này sẽ in cột đầu tiên, sau đó thoát ra

Vấn đề duy nhất là nếu bạn có lệnh Foo Skype, điều này cũng sẽ nhận. Để loại bỏ điều đó, bạn sẽ phải thực hiện một số bước chân ưa thích hơn:

ps -eo pid,comm | while read pid command 
do 
    if [[ "$command" = "Skype" ]] 
    then 
     echo $pid 
     break 
    fi 
done 

while read đang đọc hai biến. Bí quyết là read sử dụng khoảng trắng để chia các biến mà nó đọc. Tuy nhiên, vì chỉ có hai biến, biến cuối cùng sẽ chứa phần còn lại của toàn bộ dòng. Vì vậy, nếu lệnh là Skype Controller, toàn bộ lệnh sẽ được đưa vào $command mặc dù có một khoảng trống trong đó.

Bây giờ, chúng tôi không phải sử dụng cụm từ thông dụng. Chúng ta có thể so sánh lệnh với sự bình đẳng.

Quá trình này dài hơn, nhưng bạn thực sự đang sử dụng ít lệnh hơn và ít đường ống hơn. Hãy nhớ awk đang lặp qua từng dòng. Tất cả những gì bạn đang làm ở đây là làm cho nó rõ ràng hơn. Cuối cùng, điều này thực sự hiệu quả hơn nhiều so với những gì ban đầu bạn có.

1

Nếu pgrep khả dụng trên máy Mac, bạn có thể sử dụng pgrep '^Skype$'. Điều này sẽ liệt kê id quá trình của tất cả các quá trình được gọi là Skype.

Bạn đã sử dụng dấu ngoặc kép sai trong kịch bản của bạn:

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

hoặc

pgrep "^$1$" 
1

Vấn đề với ví dụ thứ hai của bạn là $ 1 là trong dấu ngoặc kép duy nhất, trong đó ngăn chặn bash từ mở rộng biến . Đã có một tiện ích hoàn thành những gì bạn muốn mà không cần phân tích cú pháp đầu ra ps theo cách thủ công.

pgrep "$1" 
0

Sử dụng dấu ngoặc kép để cho phép bash thực hiện thay thế biến. Dấu nháy đơn vô hiệu hóa cơ chế thay thế biến bash.

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

Tôi muốn để một cái gì đó như:

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

==== CẬP NHẬT ====

Sử dụng tham số mà không có dấu ngoặc kép và sử dụng dấu ngoặc đơn cho awk

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

Bạn có thể thực hiện việc này trong AppleScript:

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

có nghĩa là bạn có thể sử dụng 'osascript' để có được PID từ bên trong một kịch bản shell:

$ 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

Bạn có thể định dạng đầu ra của ps sử dụng -o [trường], ...và danh sách theo tên quá trình sử dụng C [command_name], tuy nhiên, ps sẽ vẫn in tiêu đề cột, có thể được loại bỏ bằng đường ống thông qua grep -v PID

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

nơi $ 1 sẽ là tên lệnh (trong trường hợp này Skype)

1

Phương pháp 1 - Sử dụng awk

Tôi không thấy bất kỳ lý do gì để sử dụng cờ -l (dạng dài), tôi cũng không thấy bất kỳ lý do gì để sử dụng grep và awk cùng một lúc: awk có khả năng grep được tích hợp sẵn.Đây là kế hoạch của tôi: sử dụng ps và đầu ra chỉ 2 cột: pid và lệnh, sau đó sử dụng awk để chọn ra những gì bạn muốn:

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

Cách 2 - Sử dụng bash

Phương pháp này có ưu điểm là nếu bạn đã có kịch bản trong bash, bạn thậm chí không cần awk, mà tiết kiệm một quá trình. Giải pháp dài hơn phương pháp khác, nhưng rất thẳng về phía trước.

#!/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 
} 
Các vấn đề liên quan