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 -