Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

I have piped line in bash script and want to check if pipe has data, before feeding program

Searching I found about test -t 0 but it doesn't work here. Always returns false. So how to be sure that pipe has data?


I'm providing example:

echo "string" | [ -t 0 ] && echo "empty" || echo "fill"
output: fill

echo "string" | tail -n+2 | [ -t 0 ] && echo "empty" || echo "fill"
output: fill

share|improve this question
    
See also unix.stackexchange.com/questions/13326/…; I'm not voting to close as a duplicate because that question focused on the case of sending email. –  Gilles Feb 29 '12 at 11:21
    
I am surprised nobody mentioned calling poll() with timeout of 0. I am goign to try this right now :) –  Olga Chotinun May 4 at 21:28

3 Answers 3

up vote 15 down vote accepted

There's no way to peek at the content of a pipe, nor is there a way to read a character to the pipe then put it back. The only way to know that a pipe has data is to read a byte, and then you have to get that byte to its destination.

So do just that: read one byte; if you detect an end of file, then do what you want to do when the input is empty; if you do read a byte then fork what you want to do when the input is not empty, pipe that byte into it, and pipe the rest of the data.

first_byte=$(dd bs=1 count=1 2>/dev/null | od -t o1 -A n)
if [ -z "$first_byte" ]; then
  # stuff to do if the input is empty
else
  {
    printf "\\${first_byte# }"
    cat
  } | {
    # stuff to do if the input is not empty
  }      
fi

The ifne utility from Joey Hess's moreutils runs a command if its input is empty. It usually isn't installed by default, but it should be available or easy to build on most unix variants. If the input is empty, ifne does nothing and returns the status 0, which is slightly cumbersome if you want to do something when the input is empty as well.

ifne sh -c 'do_stuff_with_input || exit 255'
if [ $? -eq 255 ]; then echo "empty"; fi

test -t 0 has nothing to do with this; it tests whether standard input is a terminal. It doesn't say anything one way or the other as to whether any input is available.

share|improve this answer
    
OK, thanks. I'll use temp file. I found in the meantime there is ifne command from moreutils deb package that does exactly that, but it's not on my system. –  zetah Feb 29 '12 at 11:28
    
It should be possible to write a ~10-lines C program which uses select(2) to check whether there is data available from a pipe, and use that one for the shell script. Note that this only works for named pipes though. –  radiospiel Mar 18 '14 at 20:37
    
@radiospiel select tells you if a pipe has data now. If the answer is no, it doesn't tell you whether data will come along later. –  Gilles Mar 18 '14 at 20:46
    
IIRC on some Unices (HPUX?), stat(2)/fstat(2) on a pipe gives you (in st_size) how much it contains ATM. –  Stéphane Chazelas Mar 18 '14 at 21:43
    
The first line will make the script wait endlessly if there is no input on stdin. –  Suzana_K May 27 at 0:04

You may use test -s /dev/stdin (in an explicit subshell) as well.

# test if a pipe is empty or not
echo "string" | 
    (test -s /dev/stdin && echo 'pipe has data' && cat || echo 'pipe is empty')

echo "string" | tail -n+2 | 
    (test -s /dev/stdin && echo 'pipe has data' && cat || echo 'pipe is empty')

: | (test -s /dev/stdin && echo 'pipe has data' && cat || echo 'pipe is empty')
share|improve this answer
    
Doesn't work for me. Always says pipe is empty. –  amphetamachine Dec 15 '14 at 16:53

This seems to be a reasonable ifne implementation in bash if you're ok with reading the whole first line

ifne () {
        read line || return 1
        (echo "$line"; cat) | eval "$@"
}


echo hi | ifne xargs echo hi =
cat /dev/null | ifne xargs echo should not echo
share|improve this answer
    
read will also return false if the input is non-empty but contains no newline character, read does some processing on its input and may read more than one line unless you call it as IFS= read -r line. echo can't be used for arbitrary data. –  Stéphane Chazelas May 27 at 8:34

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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