从后台函数打印输出后如何返回到 bash 提示?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23125527/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to return to bash prompt after printing output from backgrounded function?
提问by ff524
How can I return to my bash prompt automatically after printing output from a function that was put in the background?
打印来自后台函数的输出后,如何自动返回到我的 bash 提示?
For example, when I run the following script in a bash shell:
例如,当我在 bash shell 中运行以下脚本时:
fn(){ sleep 10 echo "Done" exit } fn &
After running the script, it immediately returns my prompt. After 10 seconds, it prints "Done" and then displays a blinking cursor on a new line:
运行脚本后,它立即返回我的提示。10 秒后,它会打印“完成”,然后在新行上显示一个闪烁的光标:
$ Done ▏
The script isn't running anymore, but I don't get my prompt back until I press Return.
该脚本不再运行,但在我按下 之前我没有得到提示Return。
Is there any way to force a return to the bash prompt after printing "Done"?
有没有办法在打印“完成”后强制返回到 bash 提示?
A related question is: Is there a way for a backgrounded task to inform the terminal to print a new prompt?However, that question asks about a backgrounded program. The answer supplied there applies to a programthat is sent to the background, but doesn't seem to work for a functionthat is sent to the background (as in the example I supplied).
一个相关的问题是:后台任务有没有办法通知终端打印新提示?但是,该问题询问的是后台程序。答案提供有适用于程序发送到后台,但似乎并没有工作一个函数发送到后台(在我提供的例子)。
To clarify: I am looking to save the entire code snippet above (e.g., as myscript.sh
) and then run it as a foreground script (e.g., as bash myscript.sh
).
澄清一下:我希望保存上面的整个代码片段(例如 as myscript.sh
),然后将其作为前台脚本(例如 as bash myscript.sh
)运行。
EDIT: The above is of course just a MWE. The context of this problem is:
编辑:以上当然只是一个 MWE。这个问题的背景是:
- User runs script
- Script submits PBS job, starts tailing the output file in the background, and calls
fn &
- User gets prompt back, may start doing other things.
- Job output appears on user's terminal when job starts running
fn
monitors the queue and killstail
when the job finishes.- Users complain about not getting prompt back (i.e., having to press Enter) after this finishes.
- 用户运行脚本
- 脚本提交 PBS 作业,在后台开始拖尾输出文件,并调用
fn &
- 用户得到提示,可以开始做其他事情。
- 当作业开始运行时,作业输出出现在用户的终端上
fn
监视队列并tail
在作业完成时终止。- 用户抱怨Enter在这完成后没有得到提示(即,必须按)。
Here's some less minimal code:
这是一些不那么最少的代码:
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 }'` echo "Job $job queued on $queue: $cmd" eval "tail -f -F $outfile 2>/dev/null &" pid=$! watch_queue &
Of course it would be a lot easier for me if my users could just pick up the job output from a separate file, or manipulate jobs between foreground and background on their own, but they can't. They can't even follow the instructions in the script to hit Enterto get the "look" of a prompt back... And I can't open another "window" - they do not have a display server.
当然,如果我的用户可以从单独的文件中获取作业输出,或者自己在前台和后台之间操作作业,那对我来说会容易得多,但他们不能。他们甚至无法按照脚本中的说明点击Enter以获取提示的“外观”......而且我无法打开另一个“窗口”——他们没有显示服务器。
采纳答案by Mohit Jain
Compile below code to file a.out
编译下面的代码到文件 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;
}
This program expects a path as command line argument. Program will open the path and write a new line to this path.
该程序需要一个路径作为命令行参数。程序将打开路径并在此路径中写入一个新行。
If this path happen to contain the file descriptor of a writable terminal running bash script, this would cause bash to catch a new prompt.
如果此路径恰好包含运行 bash 脚本的可写终端的文件描述符,这将导致 bash 捕获新提示。
Modify your shell script
修改你的 shell 脚本
fn(){
sleep 10
echo "Done"
./a.out /proc/$PPID/fd/0
}
fn &
This script would do some job (represented with sleep here) and then call the utility written previously with argument as input terminal of parent. Parent terminal would receive a new line and catch a new prompt discarding the stray command on this prompt if any.
这个脚本会做一些工作(这里用 sleep 表示),然后调用之前编写的实用程序,参数作为父级的输入终端。父终端将收到一个新行并捕获一个新提示,如果有的话,将丢弃此提示上的杂散命令。
/proc
contains directories for all processes. Name of folder matches to the pid of process.
Inbuild variable PPID
contains the parent's pid.
Inside the pid
directory, there is an fd
directory containing open streams.
0
is for input, 1
is for output and 2
is for error. There may be more open streams depending on the process. We are interested in 0
stream here.
/proc
包含所有进程的目录。文件夹的名称与进程的 pid 匹配。Inbuild 变量PPID
包含父进程的 pid。在pid
目录中,有一个fd
包含开放流的目录。
0
用于输入,1
用于输出,2
用于错误。取决于过程,可能有更多的开放流。我们对0
这里的流感兴趣。
回答by Henk Langeveld
What is the problem you're trying to solve?
您要解决的问题是什么?
Right now, this is more or less a cosmetic problem. You're still in the shell, and the prompt is still there. Just type another command and it will be executed.
现在,这或多或少是一个表面问题。您仍然在 shell 中,并且提示仍然存在。只需输入另一个命令,它就会被执行。
Alternatively, run the function in the foreground, or if you need to do something else in between, use wait
:
或者,在前台运行该函数,或者如果您需要在两者之间执行其他操作,请使用wait
:
$ fn & pid=$!
$ : something else
$ wait ${pid}
回答by Mohit Jain
similar to Henk Langevelds solution.
类似于 Henk Langevelds 解决方案。
Find the pid of your script
wait for it to finish.
echo a line
Prompt is back
Unfortunately you're going to get that blank line still
找到脚本的 pid
等待它完成。
echo a line
Prompt is back
不幸的是你仍然会得到那个空行
#!/bin/bash
fn(){
sleep 1
echo "Done"
}
fn &
PID=$!
wait $PID
echo -e ''