![systemd.service :使用 pty 强制刷新标准输出?](https://linux22.com/image/133830/systemd.service%20%EF%BC%9A%E4%BD%BF%E7%94%A8%20pty%20%E5%BC%BA%E5%88%B6%E5%88%B7%E6%96%B0%E6%A0%87%E5%87%86%E8%BE%93%E5%87%BA%EF%BC%9F.png)
我有一个服务想要在 systemd 下运行。它是用 perl 编写的,如果STDOUT
连接到终端,默认情况下输出是行缓冲的。 (这似乎类似于 蟒蛇)
结果是journalctl -f -u my.service
当缓冲区满时,输出一次到达许多行的块。
我知道我可以将服务源修改为自动刷新STDOUT
($|=1
在 perl 中)。
我知道我也可以使用unbuffer
从期望:
-ExecStart=/my/program.pl
+ExecStart=/usr/bin/unbuffer /my/program.pl
但随后我又涉及到另一个过程,这样的“解决方案”对我来说有一种难闻的味道。 (例如“Main PID”是 的unbuffer
,而不是 的/my/program.pl
)。 systemd 的全部意义就是避免像这样奇怪的 shell 解决方法。
那么有什么方法可以让这些服务不加改变地运行,让它们认为它们已连接到终端,从而刷新它们的服务STDOUT
?我看过StandardOutput=
但没有发现任何有用的东西。
答案1
不完全是,不。缓冲是通过setbuf(3)
调用为每个进程设置的,脚本语言提供不同程度的控制(TCL:完整,Perl|Python|Ruby:不完整,Shell:根本不)。您需要使用伪造终端的包装器(unbuffer、expect、tmux)或尝试不可移植的系统调用猴子修补(stdbuf
)来尝试影响输出的完成方式,或向每个应用程序添加代码,以便可以输出设置为无缓冲、行缓冲或块缓冲(或语言提供的任何子集,如果有)。一些应用程序已经有相应的标志,例如-l
of tcpdump
,或者添加这样的代码并不难:
#!/usr/bin/env perl
use strict;
use warnings;
use Getopt::Long qw(GetOptions);
GetOptions( 'l' => \my $Flag_Unbuffer ) or exit 64;
STDOUT->autoflush(1) if $Flag_Unbuffer;
print "hi\n" for 1..4;
sleep 10;
如果将其保存为lflag
可执行文件,则可以通过运行以下命令来观察行为差异:
$ ./lflag | cat
或者
$ ./lflag -l | cat