【问题标题】:Executing bash shell script accepting argument and running in background执行接受参数并在后台运行的 bash shell 脚本
【发布时间】:2020-11-02 04:21:40
【问题描述】:

我写了一个shell脚本run.sh来根据用户的输入触发一些任务

#!/bin/bash

echo "Please choose mode [1-3]: "
read MODE

case $MODE in

  1)
    echo -n "Enter iteration: "
    read TIME
    echo "Start Updating ..."
    task 1 && task 2 && task 3  
    ;;

  2)
    echo -n "Enter Seed Value: "
    read SEED
    echo "Start Updating ..."
    task 4
    task 5
    ;;

  3)
    echo -n "Enter regression minimum value: "
    read MIN
    echo "Start Updating ..."
    task 6
    ;;

  *)
    echo -n "Unknown option - Exit"
    ;;
esac

任务 1,2 ... 6 是像 /usr/bin/php task1.php $TIME 一样运行的 php 脚本,其中 $TIME 作为 php 脚本等的参数...

当我键入bash run.sh 时,脚本运行良好,但由于任务 1-6 需要很长时间才能完成,我想要一个选项,以便在我断开与终端的连接时在后台运行脚本。但是,如果我使用 bash run.sh & 运行脚本,则会遇到如下错误:

Please choose mode [1-3]: 2
-bash: 2: command not found

[5]+  Stopped                 bash run.sh

似乎 bash 将我的输入 2 解释为与 read MODE 不对应的参数,而不是导致错误的 bash run.sh 2。我无法更改脚本,使任务 1-6 像 task 1 & task 2 & 等在后台运行,因为任务 2 只能在任务 1 完成后开始运行。

我怎样才能完成我想做的事?

【问题讨论】:

  • 如果你把运行 run.shbash 进程放到后台,它怎么会要求用户输入呢?要么只是将您担心的任务放到后台,或者更好的是,不要在标准输入上要求输入,而是将 MODE_passed 作为脚本的参数。在 shell 脚本中,交互式请求输入很少是一个好主意。

标签: linux bash shell scripting


【解决方案1】:

您可以在后台按顺序运行所有这些任务subshell

( task 1; task 2; task 3 ) &

试试这个:

( echo "One"; sleep 1; echo "Two"; sleep 2; echo "Three"; sleep 3; echo "Done" ) &

你也可以让它看起来更像脚本:

(
echo "One"
sleep 1
echo "Two"
sleep 2
echo "Three"
sleep 3
echo "Done"
) &

随意使用有用的 envar $BASH_SUBSHELL

( echo $BASH_SUBSHELL; ( echo $BASH_SUBSHELL ) )

【讨论】:

  • 我还建议您考虑一下错误检测和恢复。各种任务会出现什么问题?如果在一项任务中出现问题(甚至只是发生了奇怪的事情),那么继续其余的工作是否安全?您将如何检测任务期间是否出现问题/异常情况?
  • 错误检测/响应的方法有很多。在此示例中,正在使用函数,因此您可以使用return$?。请记住,子shell 没有什么神奇/特别之处,它实际上只是另一个 bash 脚本(有点)。您可以以与在脚本中的方式非常相似的方式响应子外壳中的错误 - 回复:Gordon Davisson
【解决方案2】:

简答:在后台运行交互式程序 (/scripts) 并不能真正起作用;如果您断开与终端的连接,它的效果会更差。您应该重写脚本,使其在运行时不需要用户输入。

长答案:当您在后台运行脚本时,会发生这样的事情。请注意,事件的确切顺序可能会有所不同,因为后台脚本和前台交互式 shell 同时运行,彼此“竞速”完成任务。

  1. 您在后台使用bash run.sh & 启动脚本
  2. 您的交互式 shell 会立即为您的下一个命令做好准备,因此它会将您常用的命令提示符打印到终端。
  3. 您的脚本将提示符(“请选择模式[1-3]:”)打印到终端。
  4. 您的交互式 shell 从终端读取下一个命令。因为脚本的提示是第二个打印的,所以看起来您正在向它发送输入,但实际上最近的提示与正在接收您的输入的程序之间没有任何联系。
  5. 您的交互式 shell 尝试将您的输入(“2”)作为命令运行,但它失败了。
  6. 您的 shell 脚本终于有机会从终端发送到 read... 但它在后台,所以不允许这样做。相反,它被暂停,并打印“已停止”消息。来自bash man page,“作业控制”部分:

尝试读取的后台进程(写入何时stty tostop 生效)终端被发送一个SIGTTINSIGTTOU)信号 由内核的终端驱动程序,除非被捕获,否则它会暂停 过程。

此时,如果您想继续执行脚本并告诉它要做什么,您需要将其移至前台(例如使用fg)命令。这有点否定这里的观点。此外,它的提示(“请选择模式[1-3]:”)不会重复,因为echo命令在后台成功完成。

解决方案:基本上,编写脚本以非交互方式按必要的顺序运行任务。 @Lenna 给出了例子;听从她的建议。

【讨论】:

  • 我相信 OP 的问题更像是“基于用户输入启动后台任务的脚本”。您似乎在回答“从标准输入读取的后台任务脚本”,这不是这里要问的。如果您创建一个新问题并回答它,我相信它会为社区添加一个很好的参考点。
猜你喜欢
  • 2011-10-24
  • 1970-01-01
  • 2015-05-11
  • 2016-08-03
  • 1970-01-01
  • 1970-01-01
  • 2017-09-24
  • 2013-09-07
  • 2021-06-07
相关资源
最近更新 更多