Shell

將兩個 PID 的列表傳遞給 xargs 只會使用 ssh 殺死第一個

  • September 20, 2019

我正在檢索我想要殺死的兩個 PID 的列表。我的管道看起來像

ps -ef | grep foo | grep -v grep | awk {'print $2'} | xargs kill -9

在本地執行此操作時,兩個程序都會被殺死。但是當它與 ssh 一起使用時

ssh foo@<IP Address> "ps -ef | grep foo | grep -v grep | awk {'print $2'} | xargs kill -9"

兩個中只有一個 PID 被刪除。它輸出kill: <PID>: No such process. 它會試圖在本地殺死第二個程序嗎?

位於$2本地 shell 命令行上的雙引號內,因此由本地 shell 擴展(可能為空字元串)。

所以在遠端主機上執行的命令是這樣的:

ps -ef | grep foo | grep -v grep | awk {'print '} | xargs kill -9

awk命令是無操作的(列印所有行),xargs最終將執行:

kill -9 <all-the-words-present-in-the-output-of-ps|grep...>

這包括pid和ppid,使用者名……

此外,如果 kill 命令的 pid 在該列表中,它將殺死自己,因此無法殺死列表中剩餘的那些。

在這裡,你會想要:

ssh foo@<IP Address> 'pkill -KILL -f foo'

(殺死命令行(至少前幾千字節)包含的所有程序foo)。

或者如果遠端系統沒有pkill命令:

ssh foo@<IP Address> '
 ps -Ao pid= -o args= |
   awk "/[f]oo/ {print \$1}" |
   xargs kill -s KILL'

我們在本地使用單引號(所以那裡沒有變數擴展),而在遠端 shell 命令行中的 awk 程式碼使用雙引號,所以我們需要對 in 進行轉義$$1這樣它就不會被遠端 shell 擴展。

awk是 的超集grep,您通常不需要將它們連接在一起。最好是告訴ps只輸出你想匹配的東西,這裡假設你想foo在 ps 顯示的參數列表中搜尋你的使用-f建議。

如果你想殺死遠端使用者的所有程序(這裡是使用者 foo 和 sshing as foo),你可以這樣做:

ssh foo@<IP Address> 'kill -s KILL -- -1'

這將殺死使用者有權殺死的所有程序。對於普通使用者來說,就是所有程序的真實或保存的使用者id與殺死程序的真實或有效使用者id相同的程序。

或者:

ssh foo@<IP Address> 'pkill -KILL -U "$(id -u)"'

(或pkill -U foo)。殺死所有真實使用者ID與遠端使用者的有效使用者ID相同的程序。

或者你可以這樣做:

ssh foo@<IP Address> '
  trap "" HUP
  ps -Ao sid= -o pid= -U "$(id -u)" |
    awk "\$1 != $(ps -eo sid= -p "\$\$") {print \$2}" |
    xargs kill -s KILL'

(檢查sid以確保kill不會殺死自己、shellawkxargs,並忽略 SIGHUP 以防殺死使用者sshd程序導致發送該信號)

我們假設遠端使用者的登錄 shell 類似於 Bourne。如果遠端使用者的登錄 shell 屬於 csh 或 rc 系列,例如具有不同的語法,則必須調整這些命令。

用信號的名稱而不是數字來引用信號也是更好的做法,因為這樣會更清楚,並且信號編號可以隨系統而變化(儘管 SIGKILL 的 9 非常普遍)。

引用自:https://unix.stackexchange.com/questions/268536