1

My python script can be used in two modes:

./foo arg file

or

cat file | foo arg

This is how I decide whether stdin is a pipe or not:

if sys.stdin.isatty():
    print('not pipe\n')
else:
    print('is pipe')

and it behaves as expected:

./foo arg file
not pipe

cat file | ./foo arg
is pipe

however, in the following usage it thinks input comes from a pipe, even though the pipe is just part of the while loop:

while read F ; do foo arg $F ; done < /tmp/zz
is pipe

I am calling my script as ./foo arg file. Why does it think input is a pipe?

0

2 Answers 2

3
while read F ; do foo arg $F ; done < /tmp/zz

You're redirecting the while loop's standard input from /tmp/zz (I'm assuming this is a file). That doesn't just include the read in the condition test, it includes all the statements in the body of the loop (Unless they're otherwise redirected, of course).

Your python code is only testing if standard input is a tty/terminal, and assuming that it's a pipe otherwise. But standard input can be from any type of open file descriptor that can be read from; tty, pipe, regular file, socket, etc.

A typical approach to accepting both filenames and standard input as a program's data is looking at the number of command line arguments; if it expects filenames but there aren't enough arguments to have any, read from standard input instead.


If using bash or zsh (And maybe other shells that extend basic POSIX sh), if you want to have a program inside a loop like this read from a script's original standard input, one technique is to redirect to a different descriptor than 0 (Standard input's) and tell read to read from it instead:

while read -r -u 3 f; do foo arg "$f" ; done 3< /tmp/zz

which opens the file /tmp/zz as descriptor number 3.

Sign up to request clarification or add additional context in comments.

2 Comments

thank you, but typing the complicated construct to redirect to a different descriptor would be tedious. Is there no way to detect this in my python code? Also, please not that I cannot use number of arguments as determinant whether or not input is pipe. That would lead to chaos, if user calls with wrong number of arguments.
@400theCat surely somewhere in your program you make the determination of whether you're reading from stdin or a file. Can't you save the result of that determination somewhere?
0

Your idea would not work in a context where stdin is not bound to a TTY, but you nevertheless aren't in a pipe either.

In your concrete case, I would simply derive from the presenece or absence of the file argument, whether or not to read from stdin.

2 Comments

I cannot use number of arguments as determinant whether or not input is pipe. That would lead to chaos, if user calls with wrong number of arguments.
??? Then you have to rely on heuristics: If the last argument is a valid filename, take it as a file; otherwise read from STDIN. However, the whol thing smells to me like a badly defined user interface. Another possibility, which is adopted by many programs: Take a parameter consisting of a single dash (-) to denote this is not a file, but read from stdin here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.