Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I have a script that can accept input from STDIN, but only if the proper option is specified (-i -). I want the script to warn if STDIN is not specified but the script is being piped to (echo test | ./script.pl) or if input is redirected (./script < input.txt). I also want it to warn in the opposite case, where STDIN is specified, but the script is not being piped or input is not redirected.

I can detect if STDIN is a pipe with -p STDIN and if STDIN is redirected using (stat STDIN)[0] != 0, but when the script is run under cron, STDIN is a pipe even if the command is not being piped to. The only case under cron where STDIN is not a pipe is if it is redirected input. And testing if STDIN is empty is inadequate, because it's possible that the writing command in a pipeline will not have any output.

Is it possible to do what I'm attempting, or is a bad idea?

use Getopt::Long qw(:config bundling); GetOptions('input-file|i=s' => \my @file); my ($stdin_is_redir, $want_stdin) = !! (stat STDIN)[0]; for my $arg (@file) { my $fh; if ('-' eq $arg) { $want_stdin = 1; # This is never triggered under cron. warn "stdin isn't connected- missing pipe?\n" and next unless -p STDIN or ($stdin_is_redir and ! -t STDIN); $fh = *STDIN{IO}; } else { require Path::Tiny; my $file = path($arg); $fh = eval { $file->openr } or warn "$file: $@->{err}\n" and n +ext; } # do_something($_) while <$fh>; } # This is always triggered under cron unless $stdin_is_redir warn "stdin is connected, missing `-i -`?\n" if ! $want_stdin and ! -t STDIN and ($stdin_is_redir or -p STDIN); # Tested with: # ./script.pl # ./script.pl -i - # ./script.pl -i /dev/null # ./script.pl -i - < /dev/null # echo test | ./script.pl # echo test | ./script.pl -i -

Replies are listed 'Best First'.
Re: Warn if STDIN pipe is missing or unwanted
by haukex (Archbishop) on Jan 11, 2026 at 08:09 UTC

    Why? If feels to me to go against the *NIX principles to worry about something like that. Perhaps this is an X/Y Problem, so if you could explain why you need this that would be useful.

    If you need enough rope to shoot yourself in the foot, perhaps there's some trickery you can try like fileno(*ARGV)==fileno(*STDIN) or something, though I don't give any guarantees on that being reliable either. Also see IO::Interactive.

      Because different commands have different syntaxes/semtantics and after running other commands, I sometimes use the wrong syntax on the script in question. When that happens the script can either exit without processing the onput or hang waiting for input. Both cases seem like an error to me and if possible, should warn or fail.
        I sometimes use the wrong syntax on the script in question.

        In that case perhaps the simplest solution is to require the -i option in your script, thereby always requring one to specify a filename or "-"?

Re: Warn if STDIN pipe is missing or unwanted
by talexb (Chancellor) on Jan 13, 2026 at 14:44 UTC

    To reiterate: the UNIX philosophy for a program that handles input is to get that a) from the input filename that is specified as part of the command line, or, if there is no filename specified on the command line, b) from the input stream. The most obvious example I can think of (and there are many others) is the utility less. You can specify a filename (or a file mask), and less will open and display each of those files. If no filename is supplied, it waits for an input stream (like the command ls -lrt | less) and displays that, a page at a time.

    Alex / talexb / Toronto

    As of June 2025, Groklaw is back! This site was a really valuable resource in the now ancient fight between SCO and Linux. As it turned out, SCO was all hat and no cattle.Thanks to PJ for all her work, we owe her so much. RIP -- 2003 to 2013.

Re: Warn if STDIN pipe is missing or unwanted
by ikegami (Patriarch) on Jan 12, 2026 at 19:49 UTC
    but only if the proper option is specified

    Why break convention and add needless restrictions?

    STDIN is a pipe even if the command is not being piped to.

    It *is* being piped to. It may not have been done are your request, but it was still done.

    if STDIN is redirected using (stat STDIN)[0] != 0

    No.

    $ perl -Mv5.14 -e'say( (stat STDIN)[0] )' 60 $ perl -Mv5.14 -e'say( (stat STDIN)[0] )' </dev/null 5