views:

2161

answers:

7

I've coded a program in C that sends messages to the stdout using printf and I'm having trouble redirecting the output to a file (running from bash).

I've tried:

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

In each case, the file program.out is created but it remains empty. After the execution ends the file size is 0.

If I omit the redirection when executing the program:

./program argument

Then, all messages sent to stdout using printf are shown in the terminal.

I have other C programs for which I've no problem redirecting the output this way. Does it have to do with the program itself? with the argument passing? Where should look for the problem?

Some details about the C program:

  • It does not read anything from stdin
  • It uses BSD Internet Domain sockets
  • It uses POSIX threads
  • It assigns a special handler function for SIGINT signal using sigaction
  • It sends lots of newlines to stdout (for those of you thinking I should flush)

Some code:

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

Obviously it doesn't write anything to stdout.

I can think of two possibilities:

  1. Could it be, that it somewhere relocates stdout to another file? (For logging purposes for example…)

  2. Does it write a \0 at the start of the file and because of that the file looks like it's empty in a text editor? Have you checked the size of it?

Georg
No, I implemented the logging functions and they use printf. Those logging messages are some of the output I want to redirect
Toto
The size of the files is 0. If I omit the redirection when calling the program I can see every printf output in the terminal.
Toto
+7  A: 

Flushing after newlines only works when printing to a terminal, but not necessarily when printing to a file. A quick Google search revealed this page with further information: http://www.pixelbeat.org/programming/stdio_buffering/

See the section titled "Default Buffering modes".

You might have to add some calls to fflush(stdout), after all.

You could also set the buffer size and behavior using setvbuf.

gclj5
What about when the program ends? Shouldn't stdout be automatically flushed then?
Toto
Any link with information about this different stdout-buffer behavior between sending it to the terminal and to a file?
Toto
I edited a link into my response, so that it's easier to see for everyone. Instead of explicitly flushing every now and then, you might also change buffering behavior using setvbuf (also linked in my answer).
gclj5
A: 

Not enough writing permissions no the disk?

Georg
nope, is my home directry, and the same technique for other programs in redirecting to the same file works.
Toto
+3  A: 

Has the program terminated by the time you check the contents of the redirected file? If it's still running, your output might still be buffered somewhere up the chain, so you don't see it in the file.

Apart from that, and the other answers provided so far, I think it's time to show a representative example of the problem code. There's too many esoteric possibilities.

EDIT

From the look of the sample code, if you've got a relatively small amount of printing happening, then you're getting caught in the output buffer. Flush after each write to be sure that it's gone to disk. Typically you can have up to a page size's worth of unwritten data lying around otherwise.

In the absence of a flush, the only time you can be sure you've got everything on disk is when the program exits. Even a thread terminating won't do it, since output buffers like that aren't per-thread, they're per-process.

womble
I could not reproduce it in a small program and the original program is to big to post it. I'll try to show some code anyway.
Toto
+4  A: 

Flushing the buffers is normally handled by the exit() function, which is usually called implicitly by a return from main(). You are ending your program by raising SIGINT, and apparently the default SIGINT handler does not flush the buffers.

Take a look at this article: Applying Design Patterns to Simplify Signal Handling. The article is mostly C++, but there is a useful C example in the 2nd section, which shows how to use SIGINT to exit your program gracefully.

As for why the behavior of a terminal differs from a file, take a look at Stevens' Advanced Programing in the UNIX Environment Section 5.4 on Buffering. He says that:

Most implementations default to the following types of buffering. Standard error is always unbuffered. All other streams are line buffered if they refer to a terminal device; otherwise, they are fully buffered. The four platforms discussed in this book follow these conventions for standard I/O buffering: standard error is unbuffered, streams open to terminal devices are line buffered, and all other streams are fully buffered.
A: 

Suggestions:

  1. Redirect stderr to a file as well.
  2. Try tail -f your output file(s).
  3. Open a file and fprintf your logging (to help figure out what's going on).
  4. Search for any manual closes/duplication/piping of std* FILE handles or 1-3 file descriptors.
  5. Reduce complexity; cut out big chunks of functionality until printfs work. Then readd them until it breaks again. Continue until you identify the culprit code.
HUAGHAGUAH
A: 

Just for the record, in Perl you would use:

use IO::Handle;

flush STDOUT;
autoflush STDOUT;
ssn