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秒后,它会打印"完成",然后在新行上显示闪烁的光标:
脚本不再运行,但在按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以获得提示的"查看"…我不能再打开一个"窗口"——他们没有显示服务器。
- zsh解决方案到底有什么不适用的地方?您是否没有在zsh环境中定义的函数?
- 对我来说很管用。zsh --version报告zsh 5.0.2 (x86_64-pc-linux-gnu)。我从问题中完全使用了fn,除了3而不是10。
- @Rici我不想从提示中运行"fn&;"-我想在前台脚本中运行整个内容(fn的定义后跟"fn&;"。这对我来说是不合适的。
- 也许你需要澄清你的问题,因为我根本不清楚。这个问题似乎与你正在启动另一个zsh的实例有关。如果您使用.或等效的source执行脚本文件,它似乎可以按预期工作。我尝试了几个不同的zsh选项,但似乎没有任何帮助,我不是zsh专家(甚至不是粉丝)。祝你好运。
- @我实际上在寻找一个bash的答案,而不是zsh-我的用户担心没有得到提示,一个新的外壳可能会让他们的头爆炸:)我澄清了我的问题,谢谢你的建议。
- 你真的想要这个吗?可以在另一个窗口中打开后台进程,或者将输出写入日志文件。
你想解决的问题是什么?
现在,这或多或少是一个表面问题。你还在壳里,提示还在那里。只需键入另一个命令,它就会被执行。
或者,在前台运行该函数,或者如果需要在前台和前台之间执行其他操作,请使用wait:
1 2 3
| $ fn & pid=$!
$ : something else
$ wait ${pid} |
- 这不是我的问题我意识到这是一个美容的东西,经过一段多次从用户那里抱怨,我正在寻找任何方式。
- 这就是我用wait添加替代品的原因。好运
- Well,add some detail to the question about the real issue.你不是真的要跑到剧本里去吗?
- 上下文是:1。用户运行脚本Script submits PBS job,then calls fn &使用者迅速返回手表尾巴,工作输出到终端时工作运行,工作停止运行时杀死尾巴。
- 这是更好的。复制这个网站码到您的网站上以设置一个投票箱在您的网站上。
- 好吧,做吧!Added explanation and relevant parts of code.
- 真的,尽管"只是化妆品"是如此无助。你可能不在乎一条命令线的化妆品,但我们做了一些。这是我的一个可能的问题;我的使用者不需要超级熟悉指挥线;而且重要的是,使用者的经验应尽可能清洁。
- Doesn't do anything to deal with the issue in the question.你有没有试过要推荐什么?
编译以下代码以将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流很感兴趣。
- 我已经知道你可以按Enter继续-我在问题中说过。我要求一种自动的方法。打印"假"提示和返回"真"提示也不一样——一方面,下一行仍有闪烁的光标("假"提示输出与此函数的任何其他输出一样)。
- 我给出了答案2:解析$ps1,评估它,然后在下一行中自己打印提示
- 使用echo-ne$fake_提示
- 确保你出现假提示
- 我不能在fn中打印准确的假提示-例如,如果提示包含pwd,并且用户在运行脚本后更改了目录,那么我不知道在fn中有什么。
- 我没有尝试过,但您可以在调用此脚本之前设置父级PID。export PARENT_PID=this terminals pid,从脚本向这个PID发送sigint信号。
- 发送一个sigint到终端,希望我的用户当时没有在前台做任何重要的事情?没有:)
- 不要担心,因为重要的工作是由孩子完成的,而不是由TTY完成的。其次,发送一个终端默认处理为不退出的信号。我试过-2,它对我有用,除了在保持提示前给出不需要的^C。但我相信,你可以找到更好的信号来完成你的工作。
- 向终端发送一个sigint肯定会中断前台工作;例如,如果我运行echo"hi"; sleep 10; echo"bye"并且sigint在中间发送,则"bye"永远不会打印。我不知道一个没有不幸后果的信号,是吗?
- 你可以尝试人杀,人杀或人信号,并找到适合你的信息。
- 当以您描述的方式使用时,没有信号不会影响终端中正在进行的其他事情,因此任何信号都会有不必要的副作用(据我所知)。
- bash通过打印^C和重新打印提示,优雅地处理sigint。对其他正在运行的进程没有副作用。检查man bash航向信号,显示"信号被捕获并处理"。每个作业都会得到一个新的作业编号(对于终端是唯一的)和PID(对于系统是唯一的),因此sigint(singnal 2)由bash处理,不会与正在运行的作业交互。如果有任何正在运行的作业,它甚至不会打印不需要的^C,并且会在作业完成后得到适当的提示。(已尝试和测试)
- 当我在echo"Done"后面加上kill -2 $PARENT_PID时,运行脚本(./myscript.sh,然后在命令提示下立即运行echo"hi"; sleep 10; echo"bye"—这个信号导致"bye"不被打印。SIGINT中断命令序列。
- 好的,对不起,我以为你是在用剧本写回音"嗨"等等。在同一终端上运行sleep将被int中断,之后的所有剩余命令将被忽略(刷新)。有更好的解决方案可以继续处理管道中的当前和剩余命令。
- 你的创意给我留下了深刻的印象。对不起,到目前为止还没有一个适合我的:(
- edit3还处理您的最后一个要求+没有令人恼火的^C字符。没有睡眠中断。我只将Enter键传递给父级。
- 将Enter键传递给父级将返回shell提示,不会产生不良的副作用。Nice:))
- 注意:这也会影响父shell中的其他内容-例如,如果我运行此命令并在提示下键入一个命令而不按Enter(即,让它停在那里),当Enter键传递给父shell时,我键入的命令将运行。但我愿意容忍这种副作用。
- 如果你在
之前写了大约100个\b,你的命令将在最后一个提示时可见,但不会被执行。
- 你能给这篇文章增加一些描述性的信息吗?让读者(我)了解一下你的解决方案实际上在做什么。
- @根据你的建议省略
- 这是一个非常清晰的解决方案,但为什么我们需要C程序来做这个?不幸的是,我现在没有一台非视窗机械手(Snafu crused up my mac work-machine)。我们不能,Perhaps,直接重复一个新的文件描述符吗?(also,this particular approach won't work on OS X,as there's no process there.)
- @Elliotcable thank you.主要的想法是使用EDOCX1。我在C做这个很舒服,所以我用C。你可以使用任何其他的脚本,让你做你需要的ioctl。我从来没有在麦克环境中工作过,所以我不能这样做。但我相信(不确定)在unix和OS X中应该有一些类似之处。
类似于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 '' |
- 我需要脚本结尾,壳牌快捷地在运行fn &之后马上回来,就像原始脚本一样。其他的我不需要运行fn
- 你为什么总是想打断你的工作?你说你只是想保存/结束一次编辑会议,突然把它填满了从你的脚本上所有的胡克,然后就这样保存下来?你确定你需要一个单独的屏幕吗?
- 答案是"因为我的使用者需要它"(学习如何打开第二次SSH session对于他们中的许多人来说是困难的,因为其他原因)。另一方面,从一个背景过程中输出的数据,如果在一次编辑会议的中间出现,就不可能被拯救。
- 所以不需要!我曾经尝试过拯救它。他仍然离开安妮,尽管这是一个半途而废的时刻。生活大爆炸第1季第11集中出现if it appears halfway through something的视频截图