6

I've got a script that grabs standard input:

&process_input

sub process_input {
    while(<STDIN>) {
       $log_data .= $_;
    }
}

When I run the script:

myscript.pl -param1=a -param2=b

I get stuck in this subroutine. Everything runs OK if I do:

echo "" | myscript.pl -param1=a -param2=b

How do I determine if I even have a standard input?

I would have thought that while(<STDIN>) would return false and not run, but I'm guessing it's actually waiting for you to type something in that why it's 'stuck'.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
EDJ
  • 475
  • 1
  • 7
  • 16
  • 1
    possible duplicate of [How can I tell if STDIN is connected to a terminal in Perl?](http://stackoverflow.com/questions/528781/how-can-i-tell-if-stdin-is-connected-to-a-terminal-in-perl) – Ether Jun 04 '10 at 20:20

4 Answers4

20

You want to check where your STDIN (STanDard INput) is coming from: another application or a terminal. In your case, it's the second option, causing a read operation to stall the process until the user inputs something. For a solution, see How can I tell if STDIN is connected to a terminal in Perl?.

if (-t STDIN) {
    # input attached to terminal and will probably ask user
} else {
    # input from other process
}

There's also IO::Interactive that might do better/more reliable checking.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
MvanGeest
  • 9,536
  • 4
  • 41
  • 41
  • Thanks! Since the script can also be run by another application, I could do the -t option. – EDJ Jun 04 '10 at 18:22
2

The statement <STDIN> does not return until you press Enter on the console. If you want to get around this, I believe that you can use IO::Handle to wrap STDIN, and call $stdin->blocking(0) to enable non-blocking I/O.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JSBձոգչ
  • 40,684
  • 18
  • 101
  • 169
  • 2
    The issue is not blocking IO, but that `` (which is equivalent to `readline(*FILEHANDLE)`) is looking for a line of input. It will not return until a `\n` (well, technically an instance of the input record separator `$/`) is found. It doesn't matter whether the handle is blocking or not. Also, if you use `IO::Handle`, you can simply use it's methods on existing global handles: `STDIN->blocking(0);` – daotoad Jun 04 '10 at 19:11
1

That's normal. Standard usage for Unix tools is to use STDIN if no input file is given as an argument. Try cat, less, grep, etc. It's up to the caller to provide input, if only

tool < /dev/null

I strongly advise against trying to determine if "input" is available as it will introduce problems no matter how you achieve this. Specifically, avoid -t since it's problematic to fake a terminal when needed. Instead, rely on a more conventional interface.

If you want to make it possible to pass no input to your tool, it's weird that you'd be using STDIN in the first place. One would normally use an optional argument.

tool --foo file
tool --foo <( echo "" )

Another option would be to request that the user tells you when there is no input.

tool --batch

In order to help you with the design problems of your interface, it would really help to know what your tool does.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ikegami
  • 367,544
  • 15
  • 269
  • 518
0

Your program will continue when the user types Ctrl + D, the end-of-file character.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
OregonTrail
  • 8,594
  • 7
  • 43
  • 58