l0b0
l0b0

Reputation: 58798

How to check if stdin is from the terminal or a pipe in a shell script?

I am writing a POSIX shell script that may or may not receive input from stdin as in foo.sh < test.txt, non-interactively.

How do I check whether there is anything on stdin, to avoid halting on while read -r line...?

Upvotes: 53

Views: 29033

Answers (4)

Phil P
Phil P

Reputation: 843

To answer the question literally (but not what you actually want): read -t 0

Timeout, zero seconds.

  1. this is a race-condition, depending on when the left-hand-side is ready to provide data. You can specify -t 5 but on a thrashing system even that is problematic.
  2. read -t is not standardised in SUSv3. It is in BSD sh, bash, zsh. It's not in ksh or dash.

So you can't just use #!/bin/sh and expect to have this.

The basic problem is that even if there's nothing on stdin now, that doesn't mean there won't be soon. Invoking a program normally leaves stdin connected to the terminal/whatever, so there's no way to tell what's needed.

So, to answer your question literally, you can do it, but in practice your options are:

  1. test if stdin is a tty: [ -t 0 ]
  2. use argv to control behaviour

Upvotes: 11

darkturo
darkturo

Reputation: 124

You can easily implement a similar behaviour as the "cat" command, that is read from a list of provided files or if they're not provided, then read from the stdin.

Although you may not use this idea, I think this Linux Journal article will be interesting for you http://www.linuxjournal.com/content/determine-if-shell-input-coming-terminal-or-pipe

:-)

Upvotes: 7

dmedvinsky
dmedvinsky

Reputation: 8336

If I get the question right, you may try the following:

#!/bin/sh
if [ -t 0 ]; then
    echo running interactivelly
else
    while read -r line ; do
        echo $line
    done
fi

Upvotes: 90

Carl Norum
Carl Norum

Reputation: 224904

If you never want to run the script interactively, make it take the input file as a parameter, rather than using stdin. Some programs use a flag or a special filename to indicate that they should take input from standard input rather than from a file; that case lets you handle command line jockeying if necessary.

If you want your script to take the standard input, why don't you want to let it be interactive (or at least behave like other POSIX tools)?

Upvotes: 1

Related Questions