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.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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 :) – user113074 May 4 '15 at 21:28
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 not 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 cannot be distinguished from the command running successfully. If you want to do something if the input is empty, you need to arrange for the command not to return 0, which can be done by having the success case return a distinguishable error status:

ifne sh -c 'do_stuff_with_input && exit 255'
case $? in
  0) echo empty;;
  255) echo success;;
  *) echo failure;;
esac

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 '15 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
1  
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 '15 at 8:34

Old question, but in case someone comes across it as I did: My solution is to read with a timeout.

while read -t 5 line; do
    echo "$line"
done

If stdin is empty, this will return after 5 seconds. Otherwise it will read all the input and you can process it as needed.

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.