关于shell:如何从背景功能打印输出后返回bash提示符?

How to return to bash prompt after printing output from backgrounded function?

如何在打印后台函数的输出后自动返回bash提示?

例如,当我在bash shell中运行以下脚本时:

1
2
3
4
5
6
fn(){
        sleep 10
        echo"Done"
        exit
}
fn &

运行脚本后,它立即返回我的提示。10秒后,它会打印"完成",然后在新行上显示闪烁的光标:

1
2
$ Done

脚本不再运行,但在按return之前,不会返回提示。

打印"完成"后是否有任何方法强制返回bash提示?

一个相关的问题是:有没有一种方法可以让后台任务通知终端打印一个新的提示?然而,这个问题问的是一个后备程序。这里提供的答案适用于发送到后台的程序,但对于发送到后台的函数似乎不起作用(如我提供的示例)。

澄清:我希望保存上面的整个代码片段(例如,作为myscript.sh),然后将其作为前台脚本(例如,作为bash myscript.sh)运行。

编辑:以上当然只是一个兆瓦。这个问题的背景是:

  • 用户运行脚本
  • 脚本提交PBS作业,开始在后台跟踪输出文件,并调用fn &
  • 用户得到提示,可以开始做其他事情。
  • 作业开始运行时,作业输出显示在用户终端上。
  • fn监视队列,并在作业完成时杀死tail
  • 用户抱怨在完成后没有得到提示(即必须按下enter)。
  • 下面是一些不那么简单的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    watch_queue(){
        until [  `qstat | grep $job | wc -l` -lt 1 ]; do
            sleep 2
        done
        kill -9 $pid
        tput setaf 7
        tput setab 0
        echo"Hit ENTER to return to your command prompt."
        tput sgr0
        exit 0
    }

    cmd="something complicated that is built at runtime"
    outfile="ditto"
    queue="selected at runtime, too"

    job=`echo"cd \$PBS_O_WORKDIR  && $cmd >> $outfile" |
         qsub -q $queue -e /dev/null -o /dev/null |
         awk 'BEGIN { FS="." } { print $1 }'`

    echo"Job $job queued on $queue: $cmd"
    eval"tail -f -F $outfile 2>/dev/null &"
    pid=$!
    watch_queue &

    当然,如果我的用户能够从一个单独的文件中获取作业输出,或者自己在前台和后台之间操作作业,对我来说会容易得多,但是他们不能。他们甚至不能按照脚本中的说明来点击enterabkbbkbd以获得提示的"查看"…我不能再打开一个"窗口"——他们没有显示服务器。


    你想解决的问题是什么?

    现在,这或多或少是一个表面问题。你还在壳里,提示还在那里。只需键入另一个命令,它就会被执行。

    或者,在前台运行该函数,或者如果需要在前台和前台之间执行其他操作,请使用wait

    1
    2
    3
    $ fn & pid=$!
    $ : something else
    $ wait ${pid}


    编译以下代码以将a.out文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #include <sys/ioctl.h>
    #include <sys/stat.h>
    #include <fcntl.h>

    int main(int argc, char *argv[])
    {
        /* char buf[] ="date
    "
    ; */
        char buf[] ="
    "
    ;  /* Data to write on terminal */
        int i;
        int fd = open(argv[1], O_WRONLY);  /* Open terminal */

        /* printf("fd = %d
    "
    , fd); */
        for (i = 0; i < sizeof buf - 1; i++)  /* Write data */
          ioctl(fd, TIOCSTI, &buf[i]);
        close(fd);  /* Close file descriptor */
        return 0;
    }

    此程序需要一个路径作为命令行参数。程序将打开路径并为此路径写入新行。

    如果此路径正好包含运行bash脚本的可写终端的文件描述符,这将导致bash捕获新的提示。

    修改shell脚本

    1
    2
    3
    4
    5
    6
    fn(){
            sleep 10
            echo"Done"
            ./a.out /proc/$PPID/fd/0
    }
    fn &

    这个脚本将做一些工作(在这里用sleep表示),然后调用以前用参数编写的实用程序作为父级的输入终端。父终端将接收一个新行,并捕获一个新的提示,丢弃该提示上的杂散命令(如果有的话)。

    /proc包含所有进程的目录。文件夹名称与进程的PID匹配。inbuild变量PPID包含父级的PID。在pid目录中,有一个包含开放流的fd目录。0为输入,1为输出,2为误差。根据流程的不同,可能会有更多的开放流。我们对这里的0流很感兴趣。


    类似于Henk Langevelds解决方案。

    找到脚本的pid等待它完成。回响一条线提示返回不幸的是,你还是会得到那条空行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #!/bin/bash

    fn(){
        sleep 1
        echo"Done"

    }
    fn &
    PID=$!
    wait $PID
    echo -e ''