16

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

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

fn(){
        睡觉 10
        回声“完成”
        出口
}
fn&

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

$ 完成
▏

该脚本不再运行,但在我按下 之前我不会收到提示Return

打印“完成”后有什么方法可以强制返回到 bash 提示符?

一个相关的问题是:有没有办法让后台任务通知终端打印新的提示?但是,该问题询问的是后台程序。那里提供的答案适用于发送到后台的程序,但似乎不适用于发送到后台的函数(如我提供的示例中所示)。

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

编辑:以上当然只是一个 MWE。这个问题的上下文是:

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

这里有一些更简洁的代码:

watch_queue(){
    直到 [`qstat | grep $工作 | wc -l` -lt 1 ]; 做
        睡觉 2
    完毕
    杀死 -9 $pid
    tput setaf 7
    tput setab 0
    echo "按回车键返回命令提示符。"
    tput sgr0
    出口 0
}

cmd="运行时构建的复杂的东西"
outfile="同上"
queue="在运行时也被选中"

作业=`echo "cd \$PBS_O_WORKDIR && $cmd >> $outfile" |
     qsub -q $queue -e /dev/null -o /dev/null |
     awk '开始 { FS="." } { 打印 $1 }'`

echo "在 $queue 上排队的作业 $job: $cmd"
eval "tail -f -F $outfile 2>/dev/null &"
pid=$!
watch_queue &

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

4

4 回答 4

5

您要解决的问题是什么?

现在,这或多或少是一个外观问题。你还在 shell 中,提示仍然存在。只需键入另一个命令,它将被执行。

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

$ fn & pid=$!
$ : something else
$ wait ${pid}
于 2014-04-17T08:36:15.747 回答
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;
}

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

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

修改你的 shell 脚本

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

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

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

于 2014-04-17T06:01:44.320 回答
0

类似于 Henk Langevelds 解决方案。

找到你的脚本的 pid
等待它完成。
回显一行
提示又回来了
不幸的是,您仍然会得到那个空白行

#!/bin/bash

fn(){
    sleep 1
    echo "Done"

}
fn &
PID=$!
wait $PID
echo -e ''
于 2014-04-17T12:34:06.213 回答
0

你可以告诉你的用户再次点击返回,而不是仅仅点击 ctrl+c (这可能会意外地取消东西)。这会给你一个整洁的新提示。

Bash 真的是一团糟。bash 的开发人员不应将命令提示符后的区域视为消息的垃圾场。这是可怕的用户体验。哈哈

于 2021-01-17T14:28:04.383 回答