gpt4 book ai didi

bash - 后台作业的乱码输出

转载 作者:行者123 更新时间:2023-11-29 09:15:21 24 4
gpt4 key购买 nike

我试图在 bash 脚本中逐行收集多个子进程的输出,以便将其转发给另一个进程。

我发现没有任何东西可以保证子流程的输出不会混合,但对我来说重要的是每条输出线都正确地输出。输出之间的顺序无关紧要。

这是一个混合/乱码输出的例子:

#!/bin/bash

for i in {1..1000}; do
( { echo BEGIN; dmesg; echo END; } | tr -d '\n'; echo ) &
done

wait

运行这个:

$ ./test_output.sh | perl -ne 'print "$1\n" if m/(.{1,20}BEGIN.{0,20})/' | head
0.000000] SRAT: PXMBEGIN[ 0.000000] Initi
ME through PCIe PME BEGIN[ 0.000000] Initi
ME through PCIe PME BEGIN[ 0.000000] Initi
[ 0.209816] pci 0BEGIN[ 0.000000] Initi
ciehp 0000:00:16.1:pBEGIN[ 0.000000] Initi
CI: Updating contextBEGIN[ 0.000000] Initi
l family 2[ 0.588BEGIN[ 0.000000] Initi
ME through PCIe PME BEGIN[ 0.000000] Initi
CI: Updating contextBEGIN[ 0.000000] Initi
3922 pages, LIFO batBEGIN[ 0.000000] Initi

你可以看到几行混合内容。

当然,没有 & 一切都很好。

所以现在,我别无选择,只能将每个 child 的输出重定向到一个文件,然后在一个很大的wait之后,cat所有这些文件。

使用 GNU parallel 运行相同的程序可以完成部分工作,但在我的环境中这不是一个选项。

GNU parallel makes sure output from the commands is the same output as you would get had you run the commands sequentially. This makes it possible to use output from GNU parallel as input for other programs.

因此 GNU parallel 将在每个作业完成后立即写入每个作业输出,并且注意不要混合输出。那挺好的。但我也有兴趣尽快获得每项工作的输出,即不等待工作退出。有一个“-u”开关,但它会混合作业输出。

我需要使用 fifo、select 甚至编写 perl 脚本吗?

--

我想我已经找到了输出在 man 7 管道中混合的原因/方式/时间

POSIX.1-2001 says that write(2)s of less than PIPE_BUF bytes must be atomic: the output data is written to the pipe as a contiguous sequence. Writes of more than PIPE_BUF bytes may be nonatomic: the kernel may interleave the data with data written by other processes. POSIX.1-2001 requires PIPE_BUF to be at least 512 bytes. (On Linux, PIPE_BUF is 4096 bytes.)

最佳答案

这是我的第一次抽奖。这是一个简单的脚本,它在后台启动 stdin 上给出的所有命令(不确定这是我想要的)并逐行收集这些命令的输出。

#!/usr/bin/env perl

use strict;
use warnings;

use IO::Select;
use POSIX qw(strftime);


my $SELECT_TIMEOUT = 1;
my $TAG_SEPARATOR = '|';
my $TAG_TIMESTAMP_FORMAT = '%Y-%m-%dT%H:%M:%S';


sub multiplex {
my @commands = @_;
my %tags = (); # fd -> cmd

my $sel = IO::Select->new();

for my $cmd (@commands) {
$cmd =~ s/^\s+|\s+$//g;

my $fd;
if (!open($fd, "-|", $cmd)) {
warn "Cannot start '$cmd': $!";
next;
}
else {
$tags{$fd} = $cmd;
$sel->add($fd);
}
}


while ($sel->handles > 0) {
my @handles = $sel->can_read($SELECT_TIMEOUT);

# maybe something went wrong
if (!@handles) {
for my $fd ($sel->has_exception($SELECT_TIMEOUT)) {
$sel->remove($fd);
}
next;
}

my $now = strftime($TAG_TIMESTAMP_FORMAT, localtime(time()));

for my $fd (@handles) {
if (defined(my $line = <$fd>)) {
if ($TAG_SEPARATOR) {
$line = join($TAG_SEPARATOR, $now, $tags{$fd}, $line);
}
print $line;
}
else {
# EOF
$sel->remove($fd);
}
}
}
}




multiplex(<STDIN>);

关于bash - 后台作业的乱码输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16509345/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com