How can I detect if my shell script is running through a pipe?

Viewed 90778

How do I detect from within a shell script if its standard output is being sent to a terminal or if it's piped to another process?

The case in point: I'd like to add escape codes to colorize output, but only when run interactively, but not when piped, similar to what ls --color does.

6 Answers

In a pure POSIX shell,

if [ -t 1 ] ; then echo terminal; else echo "not a terminal"; fi

returns "terminal", because the output is sent to your terminal, whereas

(if [ -t 1 ] ; then echo terminal; else echo "not a terminal"; fi) | cat

returns "not a terminal", because the output of the parenthetic element is piped to cat.


The -t flag is described in man pages as

-t fd True if file descriptor fd is open and refers to a terminal.

... where fd can be one of the usual file descriptor assignments:

The command test (builtin in Bash), has an option to check if a file descriptor is a tty.

if [ -t 1 ]; then
    # Standard output is a tty
fi

See "man test" or "man bash" and search for "-t".

You don't mention which shell you are using, but in Bash, you can do this:

#!/bin/bash

if [[ -t 1 ]]; then
    # stdout is a terminal
else
    # stdout is not a terminal
fi

The following code (tested only in Linux Bash 4.4) should not be considered portable nor recommended, but for the sake of completeness here it is:

ls /proc/$$/fdinfo/* >/dev/null 2>&1 || grep -q 'flags:    00$' /proc/$$/fdinfo/0 && echo "pipe detected"

I don't know why, but it seems that file descriptor "3" is somehow created when a Bash function has standard input piped.

Related