3

I am extending an existing C project that prints all information to stdout with printf. I would like to have this information printed both to stdout AND to a log file.

If I were a contributor to the original project, I would just substitute all printf calls with my custom log function. Alas, I am not, so here's my question:

Is it possible to redirect printf so that a single call prints both to stdout and to file?

I know this is a long shot but, if it were possible, I could obtain what I want without having to modify the original code.

EDIT: Thank you for the answer and comments about the tee command. However, I am looking for a way to do it directly in the C code, in an automated fashion, so that users won't have to bother using tee.

Thank you for your attention!

coccoinomane
  • 858
  • 8
  • 24

3 Answers3

8

You're looking for the tee command:

./prog | tee file

This will show the output of ./prog in stdout and it will also store it in file. Think of tee as a tee fixture in plumbing :)

UPDATE

If you don't want to force users to think about using tee, I would just make a shell script that does precisely what I showed above - invoke the program with tee - and have users interact with the script only.

If that doesn't work for you, and you really want to change the source, I don't see any immediate easy solution. You could write a printf() wrapper that writes into the two streams, but then you'd have to go ahead and replace every call to printf() to your wrapper.

Filipe Gonçalves
  • 20,783
  • 6
  • 53
  • 70
  • Thank you Filipe for your answer! However, I already use shell-level redirection to generate the log file; my question is about doing it inside the C code, in an automated fashion, so that users won't have to bother using tee. That's why I think it is a long shot :-) I will edit my question to state this point more clearly. – coccoinomane Jun 16 '15 at 21:28
  • 2
    @GuidoWalterPettinari what about the `tee()` syscall? Could use it in C, right? http://linux.die.net/man/2/tee – Ricky Mutschlechner Jun 16 '15 at 21:43
  • 2
    @RickyMutschlechner The problem with `tee(2)` is that it's a one time operation, i.e., calling `tee(2)` doesn't mean "always duplicate output". You'd have to call it iteratively (see example on the manpage) – Filipe Gonçalves Jun 16 '15 at 21:56
2

Not sure if this will help, but there's a similar question in the comp.lang.c FAQ list:

http://c-faq.com/stdio/multiway.html

Bottom line: you can write your own "twowayprintf" function and then call it, but there's no way from within the program to arrange that ordinary printf calls go to two places. If you want keep the existing printf calls, you're going to have to work outside the program (with shell scripts and/or the tee command), as others have described.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • 2
    A strategically placed `#define printf` perhaps? – Jongware Jun 16 '15 at 22:11
  • Thanks for the answer, Steve! The page you linked was very useful. I wonder if @Jongware suggestion might do the trick. I have looked into variadic macros, and it seems doable. My worry is that altering a system function with a `#define` directive could cause unexpected behaviour.... – coccoinomane Jun 16 '15 at 22:54
  • 1
    You don't necessarily even need to use a variadic macro; you might be able to get away with just ``#define printf twowayprintf``. But it's definitely a hack, and not a good idea in a high-quality "production" program, because it can certainly cause problems. I believe the Standard explicitly says it's undefined to redefine standard identifiers in this way. Just a few days ago I had an obscure problem at work where someone had a `#define min(a, b) ...` and it screwed up some standard C++ headers that were included later. – Steve Summit Jun 18 '15 at 10:48
2

You could write a simple wrapper program, which:

  • Creates a pipe and forks:
    • in the child process, closes the output side of the pipe, reopens stdin as the input side of the pipe, and exec() tee, giving it an appropriate argv vector (the name of the log file)
    • in the parent process, closes the input side of the pipe, reopens stdout as the output side of the pipe, and exec()s the original executable.
rici
  • 234,347
  • 28
  • 237
  • 341