gpt4 book ai didi

c++ - 捕获标准输出压缩并使用 CTRL-C 中断会产生损坏的 zip 文件

转载 作者:行者123 更新时间:2023-12-01 14:48:45 25 4
gpt4 key购买 nike

我正在开发一个可以运行一整天的 C++ 程序。它输出到标准输出,我想压缩这个输出。未压缩的输出可能有很多 GB。启动 Bourne shell 脚本编译 C++ 代码并启动程序,如下所示:
./prog | gzip > output.gz
当我使用 CTRL-C 中断脚本时,.gz 文件总是被损坏。
当我从终端启动程序并使用 CTRL-C 中断它时,.gz 文件也总是损坏。
当我在终端上启动程序并使用 Linux killall 终止它时,.gz 文件很好。

另一方面,在终端 cat <large_file> | gzip > cat.gz可以使用 CTRL-C 中断,cat.gz 总是可以的。所以我怀疑 cat 有某种信号处理程序,我也必须在我的 C++ 程序中实现它……但是在网上查看 cat 实现时,我没有发现类似的东西。无论如何,我实现了这个:

void SignalHandler(int aSignum)
{
exit(0);
}

void Signals()
{
signal(SIGINT, SignalHandler);
signal(SIGKILL, SignalHandler);
signal(SIGTERM, SignalHandler);
}

...甚至是 bsh 脚本中的某些内容,但没有任何帮助。 CTRL-C 后,gz 文件已损坏。

问题:
  • cat 有什么我的程序没有的?
  • 如何使用 CTRL-C 和 zip 文件按顺序终止我的脚本/程序?

  • 编辑 1

    使用 zcat 打开生成的文件给出了一些输出,但随后: gzip: file.gz: unexpected end of file .在 Ubuntu 的存档管理器中打开它只会弹出一个提示 An error occurred while extracting files.
    编辑 2

    尝试冲洗;没有观察到问题的变化。

    编辑 3

    有关此问题的更多信息:缺少结尾 (EOCDR) 签名
    Fix archive (-F) - assume mostly intact archive
    zip warning: bad archive - missing end signature
    zip warning: (If downloaded, was binary mode used? If not, the
    zip warning: archive may be scrambled and not recoverable)
    zip warning: Can't use -F to fix (try -FF)

    zip error: Zip file structure invalid (file.gz)
    maot@HP-Pavilion-dv7:~/temp$ zip -FF file.gz --out file2.gz
    Fix archive (-FF) - salvage what can
    zip warning: Missing end (EOCDR) signature - either this archive
    is not readable or the end is damaged
    Is this a single-disk archive? (y/n): y
    Assuming single-disk archive
    Scanning for entries...
    zip warning: zip file empty
    maot@HP-Pavilion-dv7:~/temp$ ls -lh file2.gz
    -rw------- 1 maot maot 22 feb 15 15:18 file2.gz
    maot@HP-Pavilion-dv7:~/temp$

    编辑 4

    谢谢@Maxim Egorushkin,但它不起作用。 CTRL-C 中断脚本会杀死 prog在执行脚本的信号处理程序之前。因此,我无法向它发送信号,它已经消失了......并且没有 SignalHandler 的输出.当 prog从命令行启动, SignalHandler的输出被观察到。编:
    #include <iostream>
    #include <unistd.h>
    #include <csignal>

    void SignalHandler(int aSignum)
    {
    std::cout << "prog: Interrupt signal " << aSignum << " received.\n";
    fflush(nullptr);
    exit(0);
    }

    int main()
    {
    for (int sig = 1; sig <=31; sig++)
    {
    std::cout << " sig " << sig;
    signal(sig, SignalHandler);
    }

    while (true)
    {
    std::cout << "prog: Sleep ";
    fflush(nullptr);
    usleep(1e4);
    }
    }

    脚本:
    #!/bin/sh

    onerror()
    {
    echo "onerror(): Started."
    ps -jef | grep prog
    killall -s SIGINT prog
    exit
    }

    g++ -Wall prog.cpp -o prog

    trap onerror 2

    prog | gzip > file.gz

    结果:
    maot@HP-Pavilion-dv7:~/temp$ test.sh 
    ^Conerror(): Started.
    maot 16733 16721 16721 5781 0 16:17 pts/1 00:00:00 grep prog
    prog: no process found
    maot@HP-Pavilion-dv7:~/temp$

    编辑 5 个最小的工作解决方案

    Maxim Egorushkin 答案的实现。脚本:
    #!/bin/sh
    g++ -Wall prog.cpp -o prog
    prog | setsid gzip > file.gz & wait

    编:
    #include <iostream>
    #include <unistd.h>
    #include <csignal>

    void SignalHandler(int aSignum)
    {
    std::cout << "prog: Interrupt signal " << aSignum << " received.\n";
    exit(0);
    }

    int main()
    {
    signal(SIGINT, SignalHandler);

    while (true)
    {
    std::cout << "prog: Sleep ";
    usleep(1e4);
    }
    }

    最佳答案

    当您按 Ctrl+C 时,shell 会发送 SIGINT最后 管道中的进程,即 gzip这里。 gzip终止和下一次 prog写入 stdout它收到 SIGPIPE .

    您需要发送SIGINTprog让它冲洗它的 stdout并退出(前提是你像你一样安装了信号处理程序),这样 gzip接收其所有输出,然后终止。

    您可以按如下方式运行管道:

    prog | setsid gzip > file.gz & wait

    它使用 shell 作业控制功能在后台启动管道(即 & 符号)。那么它 wait s 终止作业。上 Ctrl+C SIGINT被发送到前台进程,即 wait 中的 shell以及同一终端进程组中的所有进程(与管道在前台且 SIGINT 仅发送到管道中的最后一个进程时不同)。 prog在那个组里。但是 gzipsetsid 开头将其放入另一个组中,这样它就不会收到 SIGINT而是在其 stdin 时终止关闭时 prog终止。

    关于c++ - 捕获标准输出压缩并使用 CTRL-C 中断会产生损坏的 zip 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60239131/

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