Terminal redirection not working on MacOS Mojave

terminal

System: MacBook Pro (early 2013), running up-to-date Mojave.

To analyze CPU utilization when an application is running I'm doing the same I've done over and again in a Linux system; running the following command on terminal:

top | grep idle

This works as it should, screen output is:

MacBook:Desktop Peregrino69$ top | grep idle
CPU usage: 13.14% user, 15.97% sys, 70.87% idle
CPU usage: 10.94% user, 8.53% sys, 80.52% idle
CPU usage: 10.95% user, 6.94% sys, 82.9% idle

However if I do

top | grep idle | tee ./utilization.txt

… unexpectedly there's no terminal output at all, and the resulting file is empty. This failing I tried

top | grep idle >> ./utilization.txt

… with the same result.

Testing redirection with a simple echo command echo hello | tee foo works as expected; the word "hello" outputs both on screen and in foo.

What's going on?

Best Answer

If STDOUT is redirected to a non-terminal (e.g. a file) a default buffer size of 4096 Byte is used. In the Terminal STDOUT defaults to line buffering.

Executing the command top | grep idle | tee >> ... will fill the 4k buffer with ~45-50 Byte/s (depending on load and sys|usr|idle split). After a while the first buffer will be written to file. Here, it took ~85 seconds to write the first buffer to the file system.


So either be patient ? or if you want the file to be updated immediately (i.e. every second), modify grep buffering:

top | grep idle --line-buffered | tee >> ./utilization.txt

Result after a few seconds:

$ cat ./utilization.txt 
CPU usage: 9.5% user, 11.49% sys, 79.44% idle 
CPU usage: 5.24% user, 10.48% sys, 84.26% idle 
CPU usage: 2.86% user, 4.74% sys, 92.39% idle 
CPU usage: 2.3% user, 1.91% sys, 96.5% idle 
CPU usage: 3.79% user, 2.25% sys, 93.95% idle 
CPU usage: 2.3% user, 3.35% sys, 94.61% idle 
CPU usage: 1.91% user, 1.91% sys, 96.16% idle 
CPU usage: 2.15% user, 2.51% sys, 95.33% idle 
CPU usage: 2.50% user, 4.29% sys, 93.20% idle 
CPU usage: 1.43% user, 1.7% sys, 97.48% idle 

If Terminal output is also required use: top | grep idle --line-buffered | tee ./utilization.txt saves the output to file and the result is visible in the Terminal window!