2016-11-19 31 views
0

我在寫一個腳本,以便用戶知道哪些數據庫,他們可以在接下來的提示輸入會從服務器獲取數據庫名稱的列表:允許用戶^ C子進程,而不是整個腳本

echo "FETCHING DB NAMES... (^C to skip)" 
ssh "[email protected]$SERV_A" "$remote_cmd" #returns space-delim db list 
echo 
printf "Which db do you want to import? >" 
read db_name 
#rest of script 

它看起來像這樣給用戶:

FETCHING DB NAMES... (^C to skip) 
db1 db2 personnel 

Which db would you like to import? > 

的問題是,獲取這些數據庫可以發生在不同的連接上需要1-10秒之間。如果用戶已經知道數據庫名稱,這可能令人沮喪。

當然,按^C作爲提示表示會殺死整個腳本而不僅僅是ssh進程。有沒有一種方法可以編寫腳本,以便他們可以取消/跳過那個ssh過程?

預先感謝您。

編輯:它本身不一定是^C,真的只是想讓用戶跳過正在運行的子進程。

+0

我不會推薦使用'control-c'作爲跳過的方法,雖然使用's','q'或其他任何可能會好的方法... –

+0

優秀點。我更新了這個問題。 –

+0

@ JamesM.Lay已經做了幾個更新,以考慮輸入塊的初始答案,並跳過整個事情,如果用戶想跳過ssh部分 – hmedia1

回答

2

這裏是SIGQUIT使用trap一個可能的方式(按Ctrl + \

(在這個例子中我是一個簡單的sleep 5 ; echo "names"替換爲您ssh命令模擬從ssh輸出)

#!/bin/bash 
bashpid="$$" 
trap "kill -9 "$bashpid"" SIGINT 

echo "FETCHING DB NAMES... (^\ to skip)"   # Fetching text 

getdbnames() { 
sleep 5 ; echo "names"       # ssh command 
} 

dbnames="$({ getdbnames & 
trap "kill -9 "$!"" SIGQUIT 
wait 
})"            # uses trap and wait to handle Ctrl+\ 

trap "" SIGQUIT         # Avoid accidental double Ctrl+\ 

if [[ -n "$dbnames" ]]; then      # Only ask import if dbnames variable 
    printf "Which db do you want to import? >" # isn't empty, otherwise 
    read db_name         # skip this whole 
fi            # section 
echo "Rest of script" 

有有很多其他方法,包括循環讀輸入語句,以及使用SIGCHLD和/或其他可能需要或不需要某些shell選項的內部消息。爲了跳過一項任務,這可能是可靠的。

這也陷阱CTRL + C,以確保它殺死了整個腳本(有時腳本產生你以後作爲不需要效果,有時用子shell方法和陷阱會導致玩了),所以這只是保證:

  • 按Ctrl + C殺死一切
  • 按Ctrl + \殺死子任務

運行腳本上述和按壓按Ctrl + C:

  • FETCHING DB NAMES... (^\ to skip) 
    ^CKilled: 9

運行上述腳本和按壓按Ctrl + \:

  • FETCHING DB NAMES... (^\ to skip) 
    ^\Rest of script

運行上面的腳本,並把它留給運行(成功ssh結果)

  • FETCHING DB NAMES... (^\ to skip) 
    names 
    Which db do you want to import? >

顯然會有一些更加精煉,它調整到您的確切的環境,但樣板在那裏。

+0

我不明白的唯一情況是您在ssh之後設置陷阱調用。在陷阱被評估之前,腳本是否會終止? –

+0

@ JamesM.Lay在更改腳本以解釋讀取塊的條件跳過之後,對我的監督。代碼已更新,並且通過在Mark Plotnicks answer中使用空白陷阱/忽略技術進行了改進,以避免意外按下ctrl + \兩次,並冒着將實際SIGQUIT發送到腳本的風險,現在已經通過Ctrl + C充分處理了這個問題。 – hmedia1

+0

太棒了!第一個版本神祕地工作.. Bash是一個祕密的野獸。 –

2

shell的trap命令可用於暫時忽略^ C。

trap "" signalname會忽略的信號,並trap - signalname將信號行爲恢復爲默認。

在這裏,我們在shell中忽略SIGINT,然後創建一個子信道,其中SIGINT恢復到其正常行爲並運行ssh

在子shell中,ssh將響應^ C,但是父shell仍然忽略SIGINT,並且如果用戶在運行ssh時鍵入^ C,則不會受到影響。

echo "FETCHING DB NAMES... (^C to skip)" 
trap "" SIGINT      # ignore ^C 
# restore default ^C behavior in subshell, 
# then run ssh to output space-delim db list 
(trap - SIGINT; ssh "[email protected]$SERV_A" "$remote_cmd") 
trap - SIGINT      # restore default ^C behavior 
echo 
printf "Which db do you want to import? >" 
read db_name 
#rest of script 
+0

「陷阱」「'是我忘記的一個方便的技巧。 +1,並在我的回答中實現了這個功能,以避免雙SIGQUIT – hmedia1

相關問題