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

3 Answers 3

up vote 9 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

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 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 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 at 21:43

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 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

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.