【问题标题】:defer pipe process to background after text match文本匹配后将管道进程推迟到后台
【发布时间】:2013-10-23 22:48:42
【问题描述】:

所以我有一个 bash 命令来启动服务器,它会在输出一些行之前输出一些内容,例如“服务器已启动,按 Control+C 退出”。如何通过管道输出此输出,因此当此行发生时,我将此进程置于后台并继续执行另一个脚本/函数(即执行需要等到服务器启动的事情,例如运行测试)

我想结束 3 个函数

  • start_server
  • run_tests
  • stop_server

我有一些类似的东西:

function read_server_output{
    while read data; do
        printf "$data"
        if [[ $data == "Server started, Press Control+C to exit" ]]; then
            # do something here to put server process in the background
            # so I can run another function
        fi
    done
}

function start_server{
    # start the server and pipe its output to another function to check its running
    start-server-command | read_server_output
}

function run_test{
    # do some stuff
}

function stop_server{
    # stop the server
}

# run the bash script code
start_server()
run_tests()
stop_tests()

相关问题可能SH/BASH - Scan a log file until some text occurs, then exit. How?

提前感谢我对此很陌生。

【问题讨论】:

    标签: linux bash shell pipe


    【解决方案1】:

    首先,关于术语的注释...

    “背景”和“前景”是控制终端的概念,即它们与您键入 ctrl+Cctrl+Z 时发生的情况有关,等(哪个进程获取信号),进程是否可以从终端设备读取(“后台”进程获取SIGTTIN,默认情况下会导致它停止),等等。

    很明显,这与您想要实现的目标无关。相反,你有一个行为不端的程序(或程序套件)需要一些特殊的溺爱:当服务器第一次启动时,它需要一些手握到某个点,之后就可以了。一旦输出一些文本字符串,手持就可以停止(请参阅您的相关问题或下面的技术)。

    这里有一个很大的潜在问题:很多程序,当它们的输出被重定向到管道或文件时,会产生 no 输出,直到它们打印出一个“块”的输出,或者退出。如果是这种情况,一个简单的:

    start-server-command | cat
    

    不会打印您要查找的行(因此这是判断您是否也必须解决此问题的一种快速方法)。如果是这样,您将需要 expect 之类的东西,这是实现您想要的完全不同的方式。

    不过,假设这不是问题,让我们尝试一种完全在 shell 中的方法。

    您需要运行start-server-command 并保存进程ID,以便您可以(最终)向它发送SIGINT 信号(如ctrl+C 如果进程是“在前台”,但是您是从脚本执行此操作,而不是从控制终端执行此操作,因此脚本无法按下任何键)。幸运的是,sh 有专门的语法。

    首先让我们创建一个临时文件:

    #! /bin/sh
    # myscript - script to run server, check for startup, then run tests
    
    TMPFILE=$(mktemp -t myscript) || exit 1    # create /tmp/myscript.<unique>
    trap "rm -f $TMPFILE" 0 1 2 3 15           # arrange to clean up when done
    

    现在启动服务器并保存它的 PID:

    start-server-command > $TMPFILE &          # start server, save output in file
    SERVER_PID=$!                              # and save its PID so we can end it
    
    trap "kill -INT $SERVER_PID; rm -f $TMPFILE" 0 1 2 3 15 # adjust cleanup
    

    现在您需要扫描$TMPFILE,直到出现所需的输出,就像在另一个问题中一样。因为这需要一定数量的轮询,所以您应该插入延迟。检查服务器是否失败并终止而没有到达“开始”点也是明智的。

    while ! grep '^Server started, Press Control+C to exit$' >/dev/null; do
        # message has not yet appeared, is server still starting?
        if kill -0 $SERVER_PID 2>/dev/null; then
            # server is running; let's wait a bit and try grepping again
            sleep 1 # or other delay interval
        else
            echo "ERROR: server terminated without starting properly" 1>&2
            exit 1
        fi
    done
    

    (这里kill -0用来测试进程是否还存在,如果不存在,则退出。“清理”kill -INT会产生错误信息,不过应该没问题。如果不存在,要么重定向那个@ 987654333@ 命令的错误输出,或调整清理或手动执行,如下所示。)

    此时,服务器正在运行,您可以进行测试。当您希望它像用户按 ctrl+C 一样退出时,向它发送 SIGINTkill -INT

    因为在trap 中设置了一个kill -INT,用于脚本何时退出 (0) 以及脚本何时被SIGHUP (1)、SIGINT (2)、SIGQUIT (3) 终止, 和SIGTERM (15)——这就是:

    trap "do some stuff" 0 1 2 3 15
    

    部分——此时你可以简单地让你的脚本退出,除非你也想专门等待服务器退出。如果你想要,也许:

    kill -INT $SERVER_PID; rm -f $TMPFILE   # do the pre-arranged cleanup now
    trap - 0 1 2 3 15                       # don't need it arranged anymore
    wait $SERVER_PID                        # wait for server to finish exit
    

    应该是合适的。

    (显然以上都没有经过测试,但这是通用框架。)

    【讨论】:

      【解决方案2】:

      可能最简单的做法是在后台启动它并阻止读取其输出。比如:

      { start-server-command & } | {
        while read -r line; do
          echo "$line"
          echo "$line" | grep -q 'Server started' && break
        done
        cat &
      }
      echo script continues here after server outputs 'Server started' message
      

      但这是一个非常丑陋的 hack。如果可以修改服务器以执行脚本可以等待的更具体的操作,那就更好了。

      【讨论】:

      • 这也应该有效,并且避免了我的方法的轮询问题。不过,与使用临时文件方法一样,隐藏服务器的输出可能会更好。 (但我认为我们都同意,“最好”的方法是修复服务器 :-))
      • 绝对修复服务器是正确的方法。正如您在回答中提到的那样,缓冲也是一个问题,而我可怕的 hack 根本无法解决这个问题。
      • cat &amp; 是干什么用的?
      • @TomRoggero cat &amp; 存在,因此来自start-server-command 的数据不会被丢弃。 while/read 循环回显输出,直到看到“服务器已启动”行,然后 cat &amp; 写入所有其余部分。
      • @WilliamPursell 谢谢!!
      猜你喜欢
      • 2015-10-03
      • 1970-01-01
      • 1970-01-01
      • 2021-04-06
      • 2015-11-20
      • 1970-01-01
      • 1970-01-01
      • 2014-10-07
      • 1970-01-01
      相关资源
      最近更新 更多