Detect If Stdin Is a Terminal or Pipe

Detect if stdin is a terminal or pipe?

Use isatty:

#include <stdio.h>
#include <io.h>
...
if (isatty(fileno(stdin)))
printf( "stdin is a terminal\n" );
else
printf( "stdin is a file or a pipe\n");

(On windows they're prefixed with underscores: _isatty, _fileno)

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

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

C - How to check if user has sent text file to stdin

You might use isatty(3) to detect if your stdin is a terminal.

You could use fstat(2) on STDIN_FILENO, e.g. to detect redirection or pipelines.

Or (on Linux) readlink(2) /proc/self/fd/0 , see proc(5)

I recommend accepting some program argument to override such an auto-detection. Read this.

Be aware that redirection and globbing is done by the shell, see this.

Detect if a command is piped or not

You can do this using os.Stdin.Stat().

package main

import (
"fmt"
"os"
)

func main() {
fi, _ := os.Stdin.Stat()

if (fi.Mode() & os.ModeCharDevice) == 0 {
fmt.Println("data is from pipe")
} else {
fmt.Println("data is from terminal")
}
}

(Adapted from https://www.socketloop.com/tutorials/golang-check-if-os-stdin-input-data-is-piped-or-from-terminal)

Detect if stdin is a tty device (terminal) or pipe in PHP?

Use posix_isatty.

This function accepts both a file descriptor (an integer) and a PHP stream. If it receives a PHP stream, it automatically attempts to cast it in order to obtain a file descriptor and use it instead.

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

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:

  • 0: standard input
  • 1: standard output
  • 2: standard error

how to tell if my stdin is coming from stdout or stderr of the piped-in process

No, it is not possible. You can differentiate stdin from a terminal by isatty() but not what sort of stream the input came from in the way you want.

How do I determine if sys.stdin is redirected from a file vs. piped from another process?

You're looking for stat macros:

import os, stat

mode = os.fstat(0).st_mode
if stat.S_ISFIFO(mode):
print "stdin is piped"
elif stat.S_ISREG(mode):
print "stdin is redirected"
else:
print "stdin is terminal"

How do I check if my program has data piped into it

Since you're using file pointers, you'll need both isatty() and fileno() to do this:

#include <unistd.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
FILE* fp = stdin;

if(isatty(fileno(fp)))
{
fprintf(stderr, "A nice msg.\n");
exit(1);
}

/* carry on... */
return 0;
}

Actually, that's the long way. The short way is to not use file pointers:

#include <unistd.h>

int main(int argc, char* argv[])
{
if(isatty(STDIN_FILENO))
{
fprintf(stderr, "A nice msg.\n");
exit(1);
}

/* carry on... */
return 0;
}

Several standard Unix programs do this check to modify their behavior. For example, if you have ls set up to give you pretty colors, it will turn the colors off if you pipe its stdout to another program.

Can not read from a pipe, and another stdin issue

Pipes don't have a size, and nor do terminals. The contents of the st_size field is undefined for such files. (On my system it seems to always contain 0, but I don't think there is any cross-platform guarantee of that.)

So your plan of reading the entire file at one go and writing it all out again is not workable for non-regular files, and is risky even for them (the read is not guaranteed to return the full number of bytes requested). It's also an unnecessary memory hog if the file is large.

A better strategy is to read into a fixed-size buffer, and write out only the number of bytes you successfully read. You repeat this until end-of-file is reached, which is indicated by read() returning 0. This is how you solve your second problem.

On a similar note, write() is not guaranteed to write out the full number of bytes you asked it to, so you need to check its return value, and if it was short, try again to write out the remaining bytes.

Here's an example:

#define BUFSIZE 65536  // arbitrary choice, can be tuned for performance

ssize_t nread;
char buf[BUFSIZE]; // or char *buf = malloc(BUFSIZE);
while ((nread = read(filedes, buf, BUFSIZE)) > 0) {
ssize_t written = 0;
while (written < nread) {
ssize_t ret = write(STDOUT_FILENO, buf + written, nread - written);
if (ret <= 0)
// handle error
written += ret;
}
}
if (nread < 0)
// handle error

As a final comment, your program lacks error checking in general; e.g. if the file cannot be opened, it will proceed anyway with filedes == -1. It is important to check the return value of every system call you issue, and handle errors accordingly. This would be essential for a program to be used in real life, and even for toy programs created just as an exercise, it will be very helpful in debugging them. (Error checking would probably have given you some clues in figuring out what was wrong with this program, for instance.)



Related Topics



Leave a reply



Submit