If you only need to know if this is a pipe or redirection, it should be sufficient to determine if stdin is a terminal or not:
if [ -t 0 ]; then
[ (aka test ) with -t equivalent to the libc isatty() function. The above will work as with something | myscript something | myscript , so with myscript < infile . This is the easiest solution, assuming your script is for interactive use.
The command [ is built into bash and some other shells, and since [ / test with -t is in POSIX , it is also portable (without relying on Linux, bash, or GNU functions).
There is one edge register, test -t also returns false if the file descriptor is invalid, but it will take a few troubles to accept it. test -e detect this, although it is assumed that you have a file name, for example /dev/stdin .
The POSIX tty command can also be used and handles the adversities above. It will print the device name tty and return 0 if stdin is a terminal, and print "not tty" and return 1 in any other case:
if tty >/dev/null ; then
(using GNU tty you can use tty -s to work silently)
A less portable way, although, of course, acceptable for typical Linux, is to use the GNU stat with its %F format specifier, this returns the text "special character file", "fifo" and "regular file" in case of terminal, pipe and redirection, respectively. stat requires a file name, so you must provide a specially named file of the form /dev/stdin , /dev/fd/0 or /proc/self/fd/0 and use -L to chase symbolic links:
stat -L -c "%F" /dev/stdin
This is probably the best way to handle non-interactive use (since you cannot make assumptions about the terminals) or to discover the actual channel (FIFO) other than redirection.
There is a small gotcha with %F in which you cannot use it to tell the difference between the terminal and some other device files, for example /dev/zero or /dev/null , which are also โcharacter special filesโ and can reasonably appear. The continuous solution is to use %t to report the type of base device (major, in hexadecimal format), assuming that you know what the basic ranges of tty device numbers are ... and it depends on whether you use styles like BSD or Unix98 ptys, or you're on a real console, by the way. In the simple case, %t will be 0, although for a channel or redirection of a normal (non-special) file.
A more general solution to this problem is to use bash read with a timeout ( read -t 0 ... ) or non-blocking I / O with GNU dd ( dd iflag=nonblock ).
The latter will allow you to detect a lack of input on stdin, dd will return the exit code from 1 if there is nothing ready to read. However, they are more suitable for non-blocking polling cycles, and not for a single check: there is a race condition when you start two or more processes in the pipeline, since each one can be ready to read before the other wrote.