1

I have a dummy question for you, I am trying to extract some lines from a file beginning by a special string of characters and to copy them into a file. I tried :

cat /dev/ttyACM0 | grep "something" > essai

The file is created but it contains nothing!

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
Nicolas
  • 11
  • 2
  • Does the `cat /dev/ttyACM0` part work right? Often with serial ports you need to run `stty` to set the speed of the port to match the speed of the device attached to the port. – Mark Plotnick Oct 30 '15 at 21:37
  • Yep, there is terminal outputs when i am not using the '>'. It shows exactly whatbi want to save – Nicolas Oct 30 '15 at 21:40
  • It may be a matter of buffering: see similar questions [Tail -f piped through grep not outputing to file, but outputs to console](http://unix.stackexchange.com/questions/65824/tail-f-piped-through-grep-not-outputing-to-file-but-outputs-to-console/65826#65826) and [Turn off buffering in pipe](http://unix.stackexchange.com/questions/25372/turn-off-buffering-in-pipe) for example – steeldriver Oct 30 '15 at 21:45
  • It's probably a buffering issue, then, since grep isn't going to stop reading until the serial port goes offline and will be storing up its output until either a few kilobytes has been amassed or it exits. On many systems you can give grep a `-m numberofmatches` argument so it'll quit after that number of matched lines. Can you describe any conditions for which grep should consider the file completely read, so it can quit? – Mark Plotnick Oct 30 '15 at 21:46
  • Using dd instead of cat would take care of the buffering issue. – mdpc Oct 30 '15 at 21:55
  • 1
    Try `grep --line-buffered < /dev/ttyACM0 > essai` - it should be line-buffered on both input and output. – Mark Plotnick Oct 30 '15 at 23:30
  • Thank you mark Plot'ick it does work now. could you explain me what was the problem with the buffer? – Nicolas Oct 31 '15 at 19:18

1 Answers1

3

For efficiency, grep and many other commands use buffered I/O, that is, they read large blocks of data at once (rather than, say, one character at a time), and do not output data until a certain amount has been amassed (rather than, say, writing a line at a time or a character at a time)

But, when a program's input is from a terminal (such as your serial port), the operating system does the program a favor and returns a line at a time (the program can change this by putting the terminal into raw or noncanonical mode; most don't).

And when a program uses the stdio library, standard output to a terminal (the documentation calls this an "interactive device") is, by default, line buffered, but output to a file or pipe is fully buffered.

A program using the stdio library can choose full buffering, line buffering, or no buffering by calling setvbuf. It can also call fflush to force a write whenever it wishes.

GNU grep takes a --line-buffered option, which will run the following code in the function that outputs a matching line:

if (line_buffered)
  fflush (stdout);

Putting all the pieces together:

With this command:

cat /dev/ttyACM0 | grep "something" > essai

cat will read a line at a time from /dev/ttyACM0. After it has amassed a few kilobytes of output, it will write to the pipe. It will repeat this until the read returns a count of zero or fails (which probably won't happen until the serial port goes offline).

grep will read a few kilobytes at a time from the pipe, and after it has amassed a few kilobytes of output, it will write to the essai fle. It will repeat this until the read returns a count of zero or fails, which will happen if and when the cat process exits.

So you won't see anything appear in the essai file until grep has found a few kilobytes' worth of matching lines.

To get output written to the file more promptly, you can give GNU grep that option:

grep --line-buffered < /dev/ttyACM0 > essai

Since it's reading from a serial port, it will be line buffered, and the --line-buffered option will make output line buffered as well.

Mark Plotnick
  • 24,913
  • 2
  • 59
  • 81