6 Answers
6

The following ifnotempty function pipes its input to the command passed as an argument, except that it does nothing if the input is empty. Use it to pipe source --foo into sink --bar by writing source --foo | pipe_if_not_empty sink --bar.

I would expect this implementation to work on all POSIX/Unix platforms, though strictly speaking it is not standards-compliant: it relies on dd not reading more than the one byte it's told to read on its standard input.

I think head -c 1 would be a suitable replacement for dd bs=1 count=1 2>/dev/null on Linux.

On the other hand, head -n 1 would not be suitable because head typically buffers its input and may read more than the one line it outputs — and since it's reading from a pipe, the extra bytes are just lost.

read -r head and even read -r -n 1 head are not suitable here because if the first character is a newline, head would be set to the empty string, making it impossible to distinguish between empty input and input starting with a blank line.

We can't just write head=$(head -c 1) because if the first character is a newline, command substitution would strip the final newline, making it impossible to distinguish between empty input and input starting with a blank line.

In bash, ksh or zsh, you can replace cat by </dev/stdin for a microscopic performance gain.

If you don't mind storing the whole intermediate data in memory, here is a very slightly simpler implementation of pipe_if_not_empty.

This function fails for me when I run echo -en "\nX" | pipe_if_not_empty mail -s "Subject line here" foo@bar.com. It thinks that line and here are both recipients of the e-mail, not tokens in the subject. I have to escape the " surrounding the subject to get it to work. However, the pipe_if_not_empty function from the accepted answer works for me even without escaping anything.
–
kuzzoorooDec 5 '14 at 21:19

Please note that the above will consider line feeds and other special characters as output, so an empty line passed to that if statement will be considered as an output. Just raise the -gt limit if your output should usually be higher than 1 byte :)