在bash中重定向C程序输出时出现问题

时间:2009-02-01 00:27:55

标签: c linux bash redirect printf

我在C中编写了一个程序,它使用printf将消息发送到stdout,我无法将输出重定向到文件(从bash运行)。

我试过了:

./program argument >> program.out
./program argument > program.out
./program >> program.out argument
./program > program.out argument

在每种情况下,都会创建文件program.out但它仍然为空。执行结束后,文件大小为0.

如果我在执行程序时省略了重定向:

./program argument

然后,使用printf发送到stdout的所有消息都显示在终端中。

我有其他C程序,我没有问题以这种方式重定向输出。 它与程序本身有关吗?与论点传递? 应该在哪里寻找问题?

关于C程序的一些细节:

  • 它没有从stdin中读取任何内容
  • 它使用BSD Internet Domain套接字
  • 它使用POSIX线程
  • 它使用sigaction
  • 为SIGINT信号分配一个特殊的处理函数
  • 它向stdout发送了许多换行符(对于那些认为我应该刷新的人)

一些代码:

int main(int argc, char** argv)
{
    printf("Execution started\n");
    do
    {        
        /* lots of printf here */
    } while (1);
    /* Code never reached */
    pthread_exit(EXIT_SUCCESS);
}

5 个答案:

答案 0 :(得分:15)

换行后的刷新仅在打印到终端时有效,但在打印到文件时不一定。 Google快速搜索在此页面中显示了更多信息:http://www.pixelbeat.org/programming/stdio_buffering/

请参阅标题为“默认缓冲模式”的部分。

毕竟,您可能必须添加一些调用fflush(stdout)。

您还可以使用setvbuf设置缓冲区大小和行为。

答案 1 :(得分:6)

刷新缓冲区通常由exit()函数处理,该函数通常由main()的return隐式调用。您通过引发SIGINT结束程序,显然默认的SIGINT处理程序不会刷新缓冲区。

看看这篇文章: Applying Design Patterns to Simplify Signal Handling。这篇文章主要是C ++,但在第二部分中有一个有用的C示例,它展示了如何使用SIGINT优雅地退出程序。

至于为什么终端的行为与文件不同, 看看史蒂文斯的Advanced Programing in the UNIX Environment关于缓冲的第5.4节。他说:

大多数实现默认使用以下类型的缓冲。 标准错误始终是无缓冲的。 如果它们引用终端设备,则所有其他流都是行缓冲的;否则,它们是完全缓冲的。 本书中讨论的四个平台遵循标准I / O缓冲的这些约定:标准错误是无缓冲的,对终端设备开放的流是行缓冲的,所有其他流都是完全缓冲的。

答案 2 :(得分:3)

在检查重定向文件的内容时程序是否已终止?如果它仍然在运行,你的输出可能仍会在链的某个地方缓冲,所以你不会在文件中看到它。

除此之外,到目前为止提供的其他答案,我认为是时候展示问题代码的代表性示例了。有太多深奥的可能性。

修改

从示例代码的外观来看,如果您发生了相对少量的打印,那么您就会陷入输出缓冲区。每次写入后刷新,以确保它已进入磁盘。通常情况下,您可以拥有最多不同页面大小的未写入数据。

在没有同花顺的情况下,唯一可以确定你已经拥有磁盘上所有内容的时间是程序退出时。即使是一个终止的线程也不会这样做,因为像这样的输出缓冲区不是每个线程,它们是每个进程。

答案 3 :(得分:0)

建议:

  1. 也将stderr重定向到文件。
  2. 尝试使用tail -f输出文件。
  3. 打开一个文件并fprintf你的日志记录(以帮助弄清楚发生了什么)。
  4. 搜索std * FILE句柄或1-3个文件描述符的任何手动关闭/复制/管道。
  5. 降低复杂性;在printfs工作之前,切掉大块功能。然后读取它们直到它再次破裂。继续,直到找出罪魁祸首代码。

答案 4 :(得分:0)

只是为了记录,在Perl中你会使用:

use IO::Handle;

flush STDOUT;
autoflush STDOUT;