【问题标题】:How to return to bash prompt after printing output from backgrounded function?从后台功能打印输出后如何返回 bash 提示符?
【发布时间】:2014-04-17 05:49:12
【问题描述】:

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

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

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

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

$ 完成 ▏

脚本不再运行,但在我按下 Return 之前我没有得到提示。

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

一个相关的问题是:Is there a way for a backgrounded task to inform the terminal to print a new prompt? 但是,该问题询问的是后台程序。那里提供的答案适用于发送到后台的 program,但似乎不适用于发送到后台的 function(如示例中所示)我提供了)。

澄清一下:我希望保存上面的整个代码 sn-p(例如,myscript.sh),然后将其作为前台脚本运行(例如,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 来获得提示的“外观”......而且我无法打开另一个“窗口” - 他们没有显示服务器。

【问题讨论】:

  • zsh 解决方案到底有什么问题?是不是你没有zsh环境中定义的函数?
  • 对我来说效果很好。 zsh --version 报告zsh 5.0.2 (x86_64-pc-linux-gnu)。我完全使用了问题中的fn,除了 3 而不是 10。
  • @rici 我不想在提示符下运行“fn &” - 我想在前台脚本中运行整个事情(fn 的定义后跟“fn &”)。这在 zsh 中对我不起作用。
  • 也许你需要澄清你的问题,因为我根本不清楚。这个问题似乎与您正在启动另一个zsh 实例有关。如果您使用.(或等效的source)执行脚本文件,它似乎可以按预期工作。我尝试了几个不同的zsh 选项,但似乎都没有帮助,而且我不是zsh 专家(甚至不是粉丝)。祝你好运。
  • @rici 我实际上是在寻找bash 的答案,而不是zsh - 我的用户因为没有得到提示而感到慌乱,一个新的外壳可能会让他们的脑袋爆炸:) 我澄清了我的问题,谢谢你的建议。

标签: bash shell background-process pbs torque


【解决方案1】:

您要解决的问题是什么?

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

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

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

【讨论】:

  • 这不能回答我的问题。我意识到这是化妆品;在用户对此进行了几十次投诉之后,我还是希望修复它。
  • 这就是我添加替代方案的原因,使用wait。祝你好运。
  • 好吧,在关于真正问题的问题中添加一些细节。您不会真的在脚本中运行sleep 10; echo 'Done',对吗?
  • 好的,完成!添加了解释和代码的相关部分。
  • 真的,不过,“这只是装饰性的”太没有帮助了。 可能不关心命令行实用程序的装饰,但我们中的一些人关心。这对我来说是一个相当大的问题;我的用户不一定对命令行非常熟悉;重要的是用户体验尽可能流畅。
【解决方案2】:

编译下面的代码到文件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 匹配。 内置变量PPID 包含父进程的 pid。 在pid 目录中,有一个fd 目录包含打开的流。 0 用于输入,1 用于输出,2 用于错误。取决于进程,可能会有更多的开放流。我们对0 感兴趣。

【讨论】:

  • 我已经知道您可以按 Enter 键继续 - 我在问题中这么说。我要求一种自动完成的方法。打印“假”提示与返回“真实”提示看起来也不一样——一方面,下一行仍然会有闪烁的光标(“假”提示输出与任何其他输出一样从这个函数)。
  • 我给出了答案 2:解析 $PS1,评估它并在下一行自己打印提示
  • 使用 echo -ne $FAKE_PROMPT
  • 并确保在 FAKE 提示符后面加上空格
  • 我无法在 fn 中打印准确的虚假提示 - 例如,如果提示包含 PWD 并且用户在运行脚本后更改了目录,我不知道 fn 中的情况。跨度>
【解决方案3】:

类似于 Henk Langevelds 解决方案。

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

#!/bin/bash

fn(){
    sleep 1
    echo "Done"

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

【讨论】:

  • 我需要在运行fn &amp; 后立即结束脚本并返回shell 提示符,就像在原始脚本中一样。否则我根本不需要在后台运行fn...
  • 你为什么希望它打断你正在做的事情?假设您正要保存/关闭一个编辑会话,突然它充满了脚本中的所有垃圾,然后就这样保存了?你肯定想要一个单独的屏幕吗?
  • 答案是“因为我的用户需要它”(对于许多人来说,学习如何打开第二个 SSH 会话会很困难,还有其他原因)。此外,如果后台进程的输出出现在编辑会话的中间,则不会保存它。
  • 所以它没有!我从来没有试图保存它。不过,如果它出现在某件事的中途,它仍然很烦人。
【解决方案4】:

您可以告诉用户再次点击返回,而不是直接按 ctrl+c(可能会意外取消内容)。这会给你一个整洁的新提示。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 1970-01-01
    相关资源
    最近更新 更多