Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect if stdout is redirected to a pipe (not to a file, character device, terminal, or socket)?

Tags:

linux

unix

posix

sh

Ideally, this would be scriptable in shell, but Perl or Python would be fine. C code could be helpful, but probably fails cost/benefit.

I recognize that redirection to a FIFO (named pipe) may be indistinguishable from a real pipe, and that is enough of an edge case that I don't really care.

Strict POSIX solutions are best, UNIX/Linux variant-independent are next best, but at least something that works on Darwin (MacOS X) is what I need right now.

Before you write your answer - I already know about test -t - that will tell me whether stdout is a terminal (in which case it is definitely not a pipe - but it will not tell me whether stdout has been redirected to a file, non-terminal character device, or UNIX-domain socket rather than a pipe.

Intended use case: I have a command that should be run within backquotes in the shell, so that it can output commands that set environment variables. I would like the command to abort with an error if stdout is not redirected to a pipe, as in that case it definitely wasn't invoked by eval `mycommand`;.

If there's some special environment variable that a shell will set when running a command within backquotes that would be helpful, but as it is likely to be specific to bash or zsh or something, pipe-detection is more important.

like image 381
Alex Dupuy Avatar asked May 26 '14 15:05

Alex Dupuy


People also ask

Where does stdout go in Linux?

Usually stdout simply goes into the buffer of your shell which is usually not buffered/recorded to any file.

How to redirect command output in Linux?

Redirection is done using either the ">" (greater-than symbol), or using the "|" (pipe) operator which sends the standard output of one command to another command as standard input.

What is redirection operator in Linux?

The redirection operator | is used to send the output of the first command as the input of the second command. For example, if I pass an initial command and then “pipe” the output generated by this command by using the | operator into a second command, it will be received as the input and then processed.

What is stdout in Linux?

stdout − It stands for standard output, and is used to text output of any command you type in the terminal, and then that output is stored in the stdout stream. stderr − It stands for standard error.


3 Answers

(my comment turned to answer per Alex Dupuy's suggestion) Since you said you can use perl, I guess you can use its -p file test operator (perldoc.perl.org/functions/-X.html); something like perl -e 'exit(-p STDOUT ? 0 : 1);' will tell you if stdout if a pipe or a fifo (without distinguishing between them).

Fwiw, calling that from the shell is exactly the reason why I used perl -e :)

like image 191
loreb Avatar answered Oct 30 '22 04:10

loreb


You could do an fstat to the file descriptor and check returning structure, for example, st_mode = 0x1000 (S_IFIFO) indicates a Named Pipe.

Example with Python:

from __future__ import print_function
import sys
import os

print(os.fstat(sys.stdout.fileno()), file=sys.stderr)

Output on windows:

C:> python test_fd.py | more
nt.stat_result(st_mode=4096, st_ino=0L, st_dev=0, st_nlink=0, st_uid=0, st_gid=0, st_size=0L, st_atime=0L, st_mtime=0L, st_ctime=0L)

C:> python test_fd.py > test_fd.txt
nt.stat_result(st_mode=33206, st_ino=16888498602769633L, st_dev=0, st_nlink=1, st_uid=0, st_gid=0, st_size=0L, st_atime= 1401119520L, st_mtime=1401119520L, st_ctime=1401119349L)
like image 41
KurzedMetal Avatar answered Oct 30 '22 04:10

KurzedMetal


In Python:

import sys
print sys.stdout.isatty()

Examples:

$ ./a
True
$ ./a | less
False
like image 43
Omer Dagan Avatar answered Oct 30 '22 03:10

Omer Dagan