从背景功能打印输出后如何返回bash提示?

ff5*_*524 10 bash shell background-process pbs torque

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

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

fn(){
        sleep 10
        echo "Done"
        exit
}
fn &

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

$ Done
?

脚本不再运行了,但是在我按下之前我没有收到提示Return.

打印"完成"后有没有办法强制返回bash提示符?

一个相关的问题是:是否有办法让后台任务通知终端打印新提示?但是,这个问题询问了一个背景计划.提供有答案适用于程序发送到后台,但似乎并没有为工作函数发送到后台(在我提供的例子).

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

编辑:以上当然只是一个MWE.这个问题的背景是:

  1. 用户运行脚本
  2. 脚本提交PBS作业,开始在后台拖尾输出文件,然后调用 fn &
  3. 用户得到提示,可能会开始做其他事情.
  4. 作业开始运行时,作业输出显示在用户终端上
  5. fn监视队列并tail在作业完成时终止.
  6. 用户抱怨在完成后没有得到快速回复(即必须按下Enter).

这里有一些不那么简单的代码:

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 &

当然,如果我的用户可以从单独的文件中获取作业输出,或者自己操作前景和后台之间的作业,那么对我来说会更容易,但他们不能.他们甚至不能按照脚本中的说明点击Enter以获得提示的"外观"......而且我无法打开另一个"窗口" - 他们没有显示服务器.

Hen*_*eld 5

你要解决的问题是什么?

现在,这或多或少是一个表面问题。您仍然在 shell 中,并且提示仍然存在。只需输入另一个命令,它就会被执行。

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

$ fn & pid=$!
$ : something else
$ wait ${pid}
Run Code Online (Sandbox Code Playgroud)

  • 然而,真的,“这只是化妆品”是如此无益。*您*可能不关心命令行实用程序的外观,但我们中的一些人确实关心。这对我来说是一个相当大的问题;我的用户不一定非常熟悉命令行;重要的是用户体验要尽可能流畅。 (6认同)

Moh*_*ain 3

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

#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>

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

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

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

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

修改你的shell脚本

fn(){
        sleep 10
        echo "Done"
        ./a.out /proc/$PPID/fd/0
}
fn &
Run Code Online (Sandbox Code Playgroud)

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

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