使用任意键停止 bash 脚本

使用任意键停止 bash 脚本

我正在编写一个自定义的 gnome-terminal 配置文件,我想用我选择的任何键停止它。按下该键后,我的意图是完成当时的所有命令并启动 su。我尝试在命令中添加 & ,但它不起作用。我附上一些信息:

我的代码:

su --command 'read -n 1 -s key; if [ "$key" == "g" ]; then su; fi;'
echo -n "W" 
sleep 0.09
echo -n "e" 
sleep 0.09
echo -n "l"
sleep 0.09
echo -n "c"
sleep 0.09
echo -n "o"
sleep 0.09 
echo -n "m"
sleep 0.09 
echo -n "e"  
sleep 0.09 

预期结果:

[角色被正确回显,直到......]

[按键按下]

Welcome

root@myuser:~#

答案1

我能得到的类似问题最接近的是这样的......

首先创建一个名为inputproc的脚本:

read -n1

然后创建一个名为 mainscript 的脚本:

array=(W e l c o m e)
buf=0
while pgrep "inputproc" > /dev/null; do
    echo -n ${array[buf]}
    ((buf++))
    sleep 0.09
done
#Insert any commands you want to run afterwards here...

然后用这个命令执行它们

./mainscript & ./inputproc

好吧,这正是您想要的。我找不到一种只用一个脚本就能做到这一点的方法,但令人惊讶的是,我找到了一种只用一个终端窗口就能做到这一点的方法。

除了明显的(使用 while 循环来检查是否输入过程在每个 echo 命令之前运行,并使用数组按顺序回显所需的字母)这可以通过运行主脚本运行时在后台运行输入过程在前台。它并非没有缺陷,但我相信这是您可以获得的最接近您想要的结果。

答案2

这在很多层面上都不起作用。主要是,bash 并不适合多线程编程。但如果你打算这样做,你必须意识到两件事:(1) 为了让你的按键读取“线程”工作,它必须拥有对 tty 的独占访问权。 (2)当你把一个进程放在后台时,它自然会从当前进程的tty复制stdin。 (3) 通常 shell 会检测到这一点并停止后台进程。

仅允许前台进程读取或写入终端(如果用户使用 stty tostop 指定)。内核的终端驱动程序会向尝试从终端读取(当 stty tostop 有效时写入)的后台进程发送 SIGTTIN (SIGTTOU) 信号,除非被捕获,否则该进程将挂起。

你可以在这里看到:

otheus@otheus-VirtualBox ~ $ ( while true; read x; do echo $x; done; ) &
[1] 2841
otheus@otheus-VirtualBox ~ $ 

[1]+  Stopped                 ( while true; read x; do
    echo $x;
done )

所以tty读取进程应该在前台。后台可以完成“工作”,但请确保先关闭标准输入:<&-

要停止“worker”进程,您必须知道它的 pid。为此,您需要在脚本中启用作业控制(默认情况下处于关闭状态)。set -m做这个。启动它并%-在按键后杀死它。您可能想确保按键循环在工作人员结束时结束。你做你的按键监控线程:

start_worker &

while jobs %- &>/dev/null; do 
   read -n 1 -s -t 1 key
   # test key
   if [[ $key == q ]]; then
      kill -1 %-
      break
   fi
fi
wait

while 条件测试作业是否仍在运行/识别。一旦结束,作业将返回 false,并且循环退出。现在,读取命令还会在 1 秒后超时。最后,循环退出后,等待以确保作业已“清理”。 (如果您正在运行其他作业,它将挂在此处。)

另一件事是:你想要完成的事情本质上是危险的。混合 root 访问和 bash 脚本编写是危险的。这里需要讨论一些主题,例如当用户按下 Control-C 或 Ctl-Z 时会发生什么。

最后,我什至不确定您是否可以将工作线程与su您的示例中的混合使用。当 su 运行时,它会将当前的 tty 更改为 root,从而阻止您的工作线程向其输出。

相关内容