允许用户使用^ C子进程而不是整个脚本

时间:2016-11-19 01:02:20

标签: linux bash ssh signals

我编写的脚本将从服务器获取数据库名称列表,以便用户知道他们可以在下一个提示中输入哪些数据库:

echo "FETCHING DB NAMES... (^C to skip)"
ssh "$user@$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,实际上只是想让用户跳过正在运行的子进程。

2 个答案:

答案 0 :(得分:2)

以下是使用trap SIGQUIT的可能方式(Ctrl + \

(对于此示例,我将您的ssh命令替换为简单的sleep 5 ; echo "names"来模拟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 以确保它杀死整个脚本(有时脚本会产生你所追求的不需要的效果,有时玩SUBhell方法和陷阱可能导致它),所以这只是为了确保:

  • 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? >

显然会有更多的精炼来调整它到你的确切环境,但样板就在那里。

答案 1 :(得分:2)

shell trap命令可用于暂时忽略^ C.

trap "" signalname将忽略信号,trap - signalname会将信号行为恢复为默认值。

在这里,我们忽略shell中的SIGINT,然后创建一个子shell,在其中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 "$user@$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