加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

bash – 后台作业的乱码输出

发布时间:2020-12-16 01:57:45 所属栏目:安全 来源:网络整理
导读:我试图逐行收集bash脚本中几个子进程的输出,以便将它转发到另一个进程. 我发现没有任何东西可以保证子过程的输出不会混合,但对我来说每条输出线都适当地输出到输出是很重要的.输出之间的顺序无关紧要. 这是混合/乱码输出的示例: #!/bin/bashfor i in {1..10
我试图逐行收集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 "$1n" 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

你可以看到混合内容的几行.

当然,没有&一切都好.

所以现在,我别无选择,只能将每个孩子的输出重定向到一个文件,然后经过一个大的等待,将所有这些文件都捕获.

使用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,选择甚至编写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>);

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读