How to determine if pipe is given

To retrieve piped input to my program I can use something like
ARGF.readlines

However, if there is no piped data, this will wait for input from the
terminal- how can I avoid this?

Thanks,
Greg Weber

greg wrote:

To retrieve piped input to my program I can use something like
ARGF.readlines

However, if there is no piped data, this will wait for input from the
terminal- how can I avoid this?

You can check if $stdin is a terminal with

$stdin.tty?

Vince

thanks, a

This kind of sucks though.

apparently in perl, if there is a piped input, ‘-’ will show up
automatically in ARGV. I think I will propose this change to Ruby.

On Thu, 28 Sep 2006, greg wrote:

thanks, a

This kind of sucks though.

why? is this hard?

stdin = ARGV.delete ‘-’

apparently in perl, if there is a piped input, ‘-’ will show up
automatically in ARGV. I think I will propose this change to Ruby.

eeeks! that’s is pure evil!

consider i have many, many programs which do things like

convert infile outfile
convert - outfile # infile on stdin
convert infile - # outfile on stdout
convert - - # infile on stdin, outfile on stdout
convert --infiles=- # list of infiles on stdin, auto-name
outfiles

this is standard unix practice (do a man on gzip, tar, etc). now, if
ruby
just started willy nilly adding a ‘-’ to the command line this technique
would
not work because it’s not just the existence of ‘-’ but the position
of it
which can have meaning.

auto-munging of ARGV is a bad idea imho.

regards.

-a

On Thu, 28 Sep 2006, greg wrote:

To retrieve piped input to my program I can use something like
ARGF.readlines

However, if there is no piped data, this will wait for input from the
terminal- how can I avoid this?

you can do something like

stdin =
if STDIN.tty?
‘’
else
STDIN.read
end

but that is an extremely bad idea because running the program under
cron, or
even using something like

program &

will cause it to hang

the best/safest approach is to always construct the command-line to
give
clear notice that stdin will be following. the most common way to do
this is
to pass ‘-’ on the command line. for example

program -
program --verbosity=4 -

etc. then, the code is simple and always correct:

parse options first

stdin = ARGV.delete ‘-’

if stdin
buf = STDIN.read
# …
else
# …
end

regards.

-a

greg wrote:

thanks, a

This kind of sucks though.

Why? One performs a test to determine if there is a pipe. That seems
reasonable.

apparently in perl, if there is a piped input, ‘-’ will show up
automatically in ARGV.

Have you done an experiment to see if this is true? In fact, the user of
the
script must provide this symbol as an argument if he wants the read a
pipe,
then the script must interpret the presence of this symbol as a signal
to
commence reading a pipe, by the way a very common *nix convention. It’s
all
very non-automatic.

I think I will propose this change to Ruby.

No sense doing it in Ruby if it isn’t done in Perl. It isn’t done in
Perl.

[email protected] wrote:

/ …

apparently in perl, if there is a piped input, ‘-’ will show up
automatically in ARGV. I think I will propose this change to Ruby.

eeeks! that’s is pure evil!

It also isn’t true. IMHO Larry Wall wouldn’t countenance such a thing.

On Sep 27, 2006, at 4:27 PM, greg wrote:

thanks, a

This kind of sucks though.

apparently in perl, if there is a piped input, ‘-’ will show up
automatically in ARGV. I think I will propose this change to Ruby.

Normally I would just nod my head in agreement with Ara, but not this
time.

I just have to say yuck with regard to using ‘-’ and the idea that
command lines
should have have an explicit syntax to indicate that the program
should read from
stdin.

If your program is prepared to deal with piped input, why are
you concerned about input coming from the keyboard? If I found a
program
that worked as:

cat file | program

and as

program < file

but did not work as just

program

I would be surprised, to say the least.

Usually the issue is the other way around where an interactive
program (vim, for
example) needs a tty device on stdin and may complain when
STDIN.tty? fails, but
I’m not sure I understand the need to complain about STDIN being tied
to a tty device
for a program that is just reading a stream of data.

The ‘-’ hack just makes me shudder. Something like ‘/dev/stdin’
would be marginally better
if you really need something like that (although not as portable).

sorry, misread some perl stuff.

How about a global flag or constant
like $PIPE set to true if there is a pipe, and otherwise set to false?

On Sep 27, 2006, at 4:42 PM, [email protected] wrote:

consider i have many, many programs which do things like

convert infile outfile
convert - outfile # infile on stdin
convert infile - # outfile on stdout
convert - - # infile on stdin, outfile on stdout
convert --infiles=- # list of infiles on stdin, auto-name
outfiles

While I understand the historical reason for such constructs, I much
prefer:

convert infile outfile
convert /dev/stdin outfile # infile on stdin
convert infile /dev/stdout # outfile on stdout
convert # infile on stdin, outfile on stdout

convert --infiles=- # list of infiles on stdin, auto-name
outfiles

Not sure about this last one. It certainly isn’t all that common.
You can get close
to this via:

cat filenames | xargs convert

with maybe an option to convert to cause it to send output to auto-
named outfiles:

cat filenames | xargs convert --inplace

I realize that some Unix systems don’t support /dev/stdin, /dev/
stdout, though…

Gary W.

greg wrote:

sorry, misread some perl stuff.

How about a global flag or constant
like $PIPE set to true if there is a pipe, and otherwise set to false?

Are you asking whether this is true, or whether it would be a good idea?
If
the latter, I personally think stuff like this should be explicitly
coded
by the programmer. There are situations where detecting the
presence/absence of a pipe may have side effects best avoided.

Of course, reasonable people may (will) differ.

On Thu, 28 Sep 2006 [email protected] wrote:

program

it may well work, but hang forever in cron though:

this is as easy to do as

infile = get_infile # oops, returned nil
system “program #{ infile }” # hangs forever

that’s also very problematic for prorgams which take two arguments:

cat infile | program - outfile
cat infile | program - - | outfile_filter > outfile

note that you cannot simply say that the abscence of infile means stdin
and
similar for outfile because

program infile_or_outfile?

i’m sure one could skin this differently, i just have debugged many hung
processes that make assumptions based on STDIN.tty?

kind regards.

-a

On Thu, 28 Sep 2006, Paul L. wrote:

[email protected] wrote:

/ …

apparently in perl, if there is a piped input, ‘-’ will show up
automatically in ARGV. I think I will propose this change to Ruby.

eeeks! that’s is pure evil!

It also isn’t true. IMHO Larry Wall wouldn’t countenance such a thing.

thanks - that’s good to know. larry++.

-a

On Thu, 28 Sep 2006, greg wrote:

sorry, misread some perl stuff.

How about a global flag or constant
like $PIPE set to true if there is a pipe, and otherwise set to false?

STDIN.tty?

-a

On Thu, 28 Sep 2006 [email protected] wrote:

While I understand the historical reason for such constructs, I much prefer:

convert infile outfile
convert /dev/stdin outfile # infile on stdin
convert infile /dev/stdout # outfile on stdout
convert # infile on stdin, outfile on stdout

agreed.

convert --infiles=- # list of infiles on stdin, auto-name
outfiles

Not sure about this last one. It certainly isn’t all that common. You can
get close to this via:

harp:~ > printf “stdin\nstdout\nstderr\n” | grep -i -f- a.rb
STDERR.puts “#{ msg } (#{ tid })”
STDIN.gets

we have lots of code that does this because they take thousands of
infiles,
hdrfiles, etc…

cheers.

-a

Didn’t you just say that this is a bad idea because of program & and
other cases?

On Sep 27, 2006, at 5:50 PM, [email protected] wrote:

it may well work, but hang forever in cron though:

Hmm. Doesn’t cron arrange for stdin and stdout to be /dev/null, in
which case
the read will simply return EOF, correct?

I just tried some experiments on Mac OS X and it seems that cron
arranges for
stdin to be an empty pipe for cron jobs.

In any case, clearly the program has been invoked incorrectly for that
context (background cron job) and it pretty much doesn’t matter what
structure
you choose for the command line arguments it is always possible to
screw it
up and provide the wrong arguments or plumb the wrong input or output
sources.

i’m sure one could skin this differently, i just have debugged many
hung
processes that make assumptions based on STDIN.tty?

I’m not sure I understand. The OP was suggesting that the program
was designed
to read from a pipe, so it really shouldn’t care if it was reading
from a tty
device, should it?

I think of this like duck typing in Ruby. As long as you can read lines
from the file descriptor and your program is designed to read lines
of text,
should you really care if stdin is associated with a file, a pipe, a
network
connection, or a tty device? Why not just read and process the data?

Gary W.

On Thu, 28 Sep 2006 [email protected] wrote:

Hmm. Doesn’t cron arrange for stdin and stdout to be /dev/null, in which
case the read will simply return EOF, correct?

I just tried some experiments on Mac OS X and it seems that cron arranges
for stdin to be an empty pipe for cron jobs.

hmmm. you are right. i had to look back at what had given me trouble
before

  • the crux of it was basically this

    input_on_stdin = not STDIN.tty?

    infile =
    if input_on_stdin
    STDIN.read
    end

so, basically assuming that the user gave input on stdin simply because
STDIN
was not a tty, which may or may not be true, as in the case where one is
running under cron or a system call from a daemon, etc.

i guess my point is that

‘stdin is not a tty’

and

‘input was given on stdin’

are two orthogonal ideas which, when merged, have bitten me in the past.
so
that’s why i’ve developed a preference for ‘-’ to signal input on stdin

  • it’s
    non-ambiguous.

In any case, clearly the program has been invoked incorrectly for that
context (background cron job) and it pretty much doesn’t matter what
structure you choose for the command line arguments it is always possible to
screw it up and provide the wrong arguments or plumb the wrong input or
output sources.

indeed.

I’m not sure I understand. The OP was suggesting that the program was
designed to read from a pipe, so it really shouldn’t care if it was reading
from a tty device, should it?

well - that is true. maybe i confused things by making it more general.
the
only reason i was making a fuss is that it’s caused me problems - as i
mentioned. probably the noise wasn’t worth it.

I think of this like duck typing in Ruby. As long as you can read lines
from the file descriptor and your program is designed to read lines of text,
should you really care if stdin is associated with a file, a pipe, a network
connection, or a tty device? Why not just read and process the data?

i think that you are quite right in this case.

cheers.

-a

I wanted the ability to optionally pipe a file, but the program would
not require a file to be piped or given as an argument. I guess the
answer is that this cannot be done. I can only allow an optional file
argument, not a pipe.

I wanted the ability to optionally pipe a file, but the program would
not require a file to be piped or given as an argument. I guess the
answer is that this cannot be done. I can only allow an optional file
argument, not a pipe.