4

So I asked a question before that added a prefix to a ping. (My last questions) that left me with the following line:

ping 8.8.8.8 |  while read line; do echo "$(date): $line"; done | grep time=

And this works GREAT. I have only one problem I can not get this to save it in a file. I tried it with just a simple redirect like so:

ping 8.8.8.8 |  while read line; do echo "$(date): $line"; done | grep time= >> googleping

But nothing gets saved in the file...

Then I tried this:

ping 8.8.8.8 |  while read line; do echo "$(date): $line"; done | grep time= | tee -a googleping

with tee to print it on screen and also save it in the file... no luck again.

(But tried echo hello | tee -a googleping and it worked fine...)

So and then I tried another while loop like so:

ping 8.8.8.8 |  while read line; do echo "$(date): $line"; done | grep time= | while read line; do echo $line; echo $line >> googleping; done

No luck again...

So is there a limit on how many pipes and redirects one line can have? And if so is there a way that I can still achive my goal of logging when I can't reach google (I just tested it with grep time= to have garuenteed output and will use grep -v time= to get all lines that have no time in them no matter waht the error may be)

So to add is that in the end I want to do in in the mac terminal, but I tried it on ubuntu server and a mac, and neither work with any of the methodes described above.

I hope someone can help me!

11
  • it works for me. Using tee -a means append. So if somehow you've created a file with lots of blank lines at top, your data is at the bottom. For testing, I'd recommend tee file or ...> file. If osx has stdbuf (I don't think it does), try adding that to the very front of your pipe list, and dbl-check how to use it with man stdbuf. Finally, Max pipes will be a minimum of 10-20. That shouldn't be a problem . Pluse-uno for really drilling down on your problem. Good luck.
    – shellter
    Commented Dec 27, 2015 at 2:07
  • I don't know what magic you are using, but it does not work for me. Can you please post the exact line that is working for you?
    – usbpc102
    Commented Dec 27, 2015 at 2:09
  • I"m not using OSX, so I think that could be the issue. I copy/pasted your 2 versions from above. Both worked. Sorry! Did you check you ls -l googleping to see if the file has any size, r.e. my comment on append. Good luck.
    – shellter
    Commented Dec 27, 2015 at 2:14
  • No my file has no size, and I'm trying this on ubuntu 15.10 (I think there are more users that know ubuntu, so I'll try to get it to work there and then see if I can understand OSX...) . And I also copied my second version again. Something is off here. :/
    – usbpc102
    Commented Dec 27, 2015 at 2:16
  • 1
    No, this is not an OS X problem. OS X is just another Unix that behaves in very much the same way in terms of simple things like this. Pipe buffer size is usually 4KB; you won't get anything until you have accumulated 4KB of data to write. Use grep --line-buffered instead to flush the buffer after every line. Alternatively, use the -c option of ping to stop after sending a certain number of packets; when it stops you'll immediately get your stuff.
    – 4ae1e1
    Commented Dec 27, 2015 at 2:31

2 Answers 2

16

The answer by hek2mgl explains that your particular issue is unrelated to the number of pipes.

But to answer the question in your title ("Is there a limit on how many pipes I can use?"), yes there is a limit on opened file descriptors, but on current systems it is significantly big (several thousands) in practice. AFAIU, POSIX guarantee a small limit (perhaps only 20). Your system has probably a file descriptor limit per process, and another file descriptor limit system wide....

To set or query that per-process file descriptor limit, you might use setrlimit(2) and getrlimit with RLIMIT_NOFILE (and the ulimit builtin of bash, or the limit builtin of zsh, in your interactive shell). You can also read /proc/self/limits on Linux (see proc(5) for more on /proc/ pseudo-files). On my Linux Debian system I have 65536 maximum file descriptors per process.

IIRC, /proc/sys/fs/file-max gives the maximum number of opened file descriptors. On My system, it is 1632058 right now.

When you have reached the file descriptor limit, the pipe(2) syscall (e.g. done by your shell for pipelines with | ....) would fail with:

EMFILE Too many file descriptors are in use by the process.

ENFILE The system limit on the total number of open files has been reached.

And open(2) can also fail for disk quota excess...

EDQUOT Where O_CREAT is specified, the file does not exist, and the user's quota of disk blocks or inodes on the filesystem has been exhausted.

See also pipe(7) and read Advanced Linux Programming; when programming in C, you should use fflush(3) appropriately and wisely.

2
  • 1
    Think you very much! This is exactly the kind of answer I was looking for in addition to get my very specific problem solved! I can't thank you enough!
    – usbpc102
    Commented Dec 27, 2015 at 14:28
  • This actually answers the question in the title! This is great. Thanks!
    – diviquery
    Commented May 28, 2021 at 12:11
2

This is not related to the number of pipes you are using. You don't see output from tee immediately because of output buffering. When grep's ouput is going to a pipe instead of a terminal, it get's block buffered. If you have enough patience, the output will appear after a while (once the buffer get's flushed).

This behaviour is implemented in the libc unless a program explicitly handles buffering on it's own. You can influence this behaviour using the stdbuf command:

ping 8.8.8.8 \
  |  while read line; do echo "$(date): $line"; done \
  | stdbuf -o0 grep time= \
  | tee -a googleping

I'm calling grep using stdbuf -o0 which shrinks the output buffer size of grep to zero length. Alternatively you can use -oL which produces line buffered output.


Sidenote: stdbuf works for your example. But if you read the man page of stdbuf carefully, you'll notice:

NOTE: If COMMAND adjusts the buffering of its standard streams ('tee' does for e.g.) then that will override corresponding settings changed by 'std‐ buf'. Also some filters (like 'dd' and 'cat' etc.) don't use streams for I/O, and are thus unaffected by 'stdbuf' settings.

That's what I told above. stdbuf works only with programs which doesn't handle buffering on their own. tee is such a program. Meaning if you further pipe from tee you cannot use stdbuf.

Not the answer you're looking for? Browse other questions tagged or ask your own question.