2016-12-25 70 views
0

我試圖創建一個腳本以在硬件防火牆上運行。防火牆正在運行一個缺乏一些工具的強化Linux,例如timeoutparallel並行啓動多個進程,並在X秒內終止所有進程

腳本根據一些標準從netstat命令收集IP地址,並將這些IP提供給腳本。

腳本本身將並行執行每個IP地址的命令,並在20秒後終止所有尚未完成的命令。

所有命令的輸出都需要通過標準輸出傳送到終端。

我來最接近的是這個劇本,我發現有些修改,以適合我的需要:

#!/bin/bash 

for cmd in "[email protected]"; do { 
    echo "Process \"$cmd\" started"; 
    $cmd & pid=$! 
    PID_LIST+=" $pid"; 
} done 

echo "Parallel processes have started"; 
sleep 5 
for id in $PID_LIST 
do 
    kill $id 
done 


echo 
echo "All processes have completed"; 

這個腳本做什麼,我需要的,但它需要INDATA是在爭論,如:

./script.sh "command IP" "command IP" 

我的第一個想法是使用「讀」來管的IP地址進入命令,所以我用

while read cmd; do... (and the rest of the script above on one line) 
替換for循環中它

發生的問題是,PID_LIST變量在while循環之外無法存活,就像上面的for循環中的例子一樣。這意味着腳本無法監視已啓動的命令的PID並在超時後將其殺死。

所以我的問題是:

  1. 是否有一個原因在for循環中仍設置在循環外部聲明的變量,而不是在一個while循環?
  2. 我是否可以在保持for循環的同時將數據傳入此腳本?例如,以類似的方式,我用while循環,使用「while read cmd do」,或以某種其他方式

我想過試圖從我的netstat命令中獲取數據一個數組,並用數組替換「$ @」,但我沒有成功。

我已閱讀Command line command to auto-kill a command after a certain amount of time,但我不覺得它回答了我的問題足以讓我達到我的目標。看起來像大多數腳本只針對於運行一個命令,而不是幾個並行。

編輯:

爲了給一些更多的信息我嘗試多一些,並發現了一些可能是我所關注的原因。 結束腳本需要在一行上運行,另一部分收集來自netstat的信息。但是,當我測試它時,我已經把腳本放在一個文件中,並將其傳輸到一個文件中,就像你說的那樣,這很好用。即使parallel.sh在一行中包含所有代碼。

作爲參考,這是並行的內部。SH

while read cmd; do { echo "Process \"$cmd\" started"; $cmd & pid=$! PID_LIST+=" $pid"; } done ; echo "Parallel processes have started"; sleep 5; for id in $PID_LIST ; do kill $id ; done 

但是,當我把該行從出parallel.sh並把它放在同一個命令行,它不工作

myoutput | while read cmd; do { echo "Process \"$cmd\" started"; $cmd & pid=$! PID_LIST+=" $pid"; } done ; echo "Parallel processes have started"; sleep 5; for id in $PID_LIST ; do kill $id ; done 

那麼,什麼是管道之間不同的進parallel.sh或有腳本的內容在同一命令行上?

似乎什麼錯誤是$ pid_list相同的運行全部在一行的腳本時while循環的空之外,同時它似乎while循環的體外存活管道傳輸到./parallel.sh

+0

你應該表現出_exactly_如何你寫了'while' /'read'循環。沒有任何理由(除了你編寫一些編碼錯誤,通常在子shell中運行循環)'while'循環不能像你想要的那樣工作。 –

+0

請勿爲此使用Bash。你生氣嗎? – Ben

+0

我沒有太多的選擇。 Perl沒有安裝。除了一些小問題,我認爲bash可以很好地工作。 – Johnathan

回答

0

如此看來,解決辦法是使用()

正如我上面所說,這個作品

myoutput | ./paralell.sh 

但不是這個

myoutput | content of script 

但少了什麼是這樣做的

myoutput | (content of script) 
+0

其他人解釋這三個例子之間的區別以及爲什麼最後一個更適合這種情況會有所幫助。 –

-1

爲可疑,你正在運行在子shell的while循環,讓你創造有儘快丟失的子shell退出的變量。見BashFAQ/024

一個更清潔的方式:

#!/bin/bash 

# enable job control 
set -m 

while read cmd; do 
    printf 'Process "%s" started\n' "$cmd" 
    $cmd & 
done < <(myoutput) 

echo "Parallel processes have started" 
sleep 5 

while read pid; do 
    kill $pid 
done < <(jobs -rp) 

wait 

相對於你的腳本的變化:

  • while循環不是在子shell執行。我們正在使用流程替換。
  • 可能最重要的變化是我們沒有保存已啓動進程的PID。
  • 我們使用jobs內建檢索子進程的PID。我們一個一個殺死他們。這比你的設計更優越,因爲有些工作可能已經終止,你可能會殺死已經停止的工作,或者更糟糕的是,其他工作可能已經開始並在此期間重複使用相同的PID!
  • 最後我們wait爲所有工作終止。

你會看到一些垃圾郵件就像標準錯誤

./myparallel: line 42: 12345 Terminated  $cmd 

。如果你想擺脫這些(以及其他可能的錯誤消息,當你殺死在結束進程),你可以用最後的循環和wait命令,像這樣:

{ 
    while read pid; do 
     kill $pid 
    done < <(jobs -rp) 

    wait 
} 2> /dev/null