1

I am trying to build a C program that tails a file using tail -f , but I would like it to do something with the data anytime something is written to the file.

I am a javascript programmer, so this next example probably won't make much sense in the context of the C language, but what I would like to do is this:

#include <stdio.h>
#include <stdlib.h>

int main (){

    printf("Tailing file");
    system("tail -f read.txt", function(){

        // this callback is called everytime new data is outputted from tail
        doSomething();
    });
    exit(0);

}

Is what I'm trying to do possible? Thanks for your help

jerry
  • 2,743
  • 9
  • 41
  • 61
  • 1
    check [popen](http://linux.die.net/man/3/popen). – BLUEPIXY Jan 22 '14 at 12:19
  • Or, if the program is more generic and sometimes you want to give it the output of `tail -f`, just read from `stdin` and from command line pipe it in. – Shahbaz Jan 22 '14 at 12:24
  • Perhaps you should start with reading a file in it's whole. If you got this working go for reading through the sources of the system command `tail` as linked by others, to then role your own. Your approach of simply starting the system command from a C file, does not to make much sense. Why not just call `tail` directly, but wrap it into a C starter. – alk Jan 22 '14 at 12:32

3 Answers3

2

I would implement something like tail in separate long running thread. Here is an example how to read opened file continuously using C.

And here you can find sources of tail program

Community
  • 1
  • 1
Dabo
  • 2,371
  • 2
  • 18
  • 26
  • 1
    I agree with @Dabo -- it's _far_ better to simply manage the reading within your own program and not rely on calling another to do this trivial work. – mah Jan 22 '14 at 12:25
  • Note: here's gnu's implementation: http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/tail.c – Shahbaz Jan 22 '14 at 12:44
  • @Shahbaz yes, this one is better. – Dabo Jan 22 '14 at 12:47
0

This is a little more complicated in C. You'll need to create another process that runs the "tail -f" command and process the stdout of this process that you redirect to your process that's running main.

Fortunately if you only want to communicate in one direction (i.e. process output of tail -f) the popen() function comes in handy.

Have a look at this Stackoverflow question for using popen: how to control popen stdin, stdout, stderr redirection?

After you have opened the pipe you'll have to retrieve the desired output using fread or other similar functions.

Community
  • 1
  • 1
LostBoy
  • 948
  • 2
  • 9
  • 21
  • 2
    Using popen (or any other similarity) to access tail to do the work is like killing a fly with a brick -- yes, it can work but there are better ways -- such as reading the file in your own code directly. Since the tail program is open source, reading it to see how it works is easily accomplished. – mah Jan 22 '14 at 12:23
  • 1
    @mah, `tail -f` keeps updating the output as the file gets appended to. Getting that functionality done right is something I personally would not want to go into when there already is `tail -f`. Take a look at the [source code](http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/tail.c) if you want to see how many things should be taken care of! – Shahbaz Jan 22 '14 at 12:29
  • @Shahbaz a problem being more difficult than you wish it to be does not justify solving it in a horrible way! It's also unlikely that everything tail does must be performed in non-generic situations. There are certain times that popen is needed, but as a proxy to non-blocking file I/O (which is all this use does -- turning it into blocking while starting up two additional processes to do so) is not of them. – mah Jan 22 '14 at 12:36
  • If the OP asked for ways to work with tail -f, I'll tell him how to do this. I assume that there's a reason why he does not want to read the file himself. – LostBoy Jan 22 '14 at 12:41
  • @mah, I agree with you, but the OP hasn't provided any context. Maybe he's best off with [another solution altogether](http://meta.stackexchange.com/q/66377/169090). There are many contexts in which `popen` on `tail` is as stupid as `cat x | program`, there are also contexts where it's ok to avoid programming for three hours just to perform some quick very light calculations on the output of `tail`. – Shahbaz Jan 22 '14 at 12:41
0

If you need to use tail -f, and you don't want to tail the file yourself, you need to open a pipe.

As others have said, popen is a good way to do this: it's like fopen except it takes a shell command string, executes that via the shell, and returns a FILE which you can read using fread. Reads from the pipe will block until data is available. You might want something roughly like:

#define BUFSZ 1024
FILE *pipe = popen("tail -f yourfile", "r");
while (you still want to tail the file) {
    char buf[BUFSZ];
    fread(buf, BUFSZ, 1, pipe);
    /* do something with the data in buf */
}

If you need to do other things while you're waiting for output from tail, you need to use pipe, which is the (lower-level) system call that popen uses behind the scenes.

benj
  • 713
  • 6
  • 12