# Pipe in cmd-line text but then reset STDIN for menu

**URL:** <https://www.ruby-forum.com/t/pipe-in-cmd-line-text-but-then-reset-stdin-for-menu/154078>\
**Category:** Ruby\
**Created:** [November 25, 2008, 5:37am UTC](https://www.ruby-forum.com/t/pipe-in-cmd-line-text-but-then-reset-stdin-for-menu/154078 "2008-11-25T05:37:36Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![starmaerker](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/e9bcb4/32.png) [@starmaerker](https://www.ruby-forum.com/u/starmaerker)\
**Post date:** [November 25, 2008, 5:37am UTC](https://www.ruby-forum.com/t/pipe-in-cmd-line-text-but-then-reset-stdin-for-menu/154078/1 "2008-11-25T05:37:36Z")

</div>

Hello,  
I’m trying to make a customized pager utility that can process  
file-contents piped in from the command line, equally well as a list of  
provided file names.  
e.g. cat testfile | my\_util.rb or my\_util.rb testfile

I’m having trouble using the pipe to get the file contents and still be  
able to use STDIN in a non-blocking way for a shell-style interactive  
menu.

For the menu, I’m using Highline::SystemExtensions: e.g.:  
while (mychar = get\_character) && (mychar.chr != “q”)  
if (mychar.chr == “x”) then  
filter\_all\_but\_selected  
end  
end

… and that works only for the case where there is no input pipe,  
instead filename(s) I get from ARGV.

Here’s what I’ve tried to get the pipe read before begining the menu,  
but thid hammers the rest of my script and my highline menu doesn’t  
work:

def fill\_pipe

# capture piped input

flags = STDIN.fcntl(Fcntl::F\_GETFL, 0)  
flags |= Fcntl::O\_NONBLOCK  
STDIN.fcntl(Fcntl::F\_SETFL, flags)  
begin  
input\_pipe = STDIN.readlines  
$working\_pipe.concat(input\_pipe)

# puts “Input pipe: #{$input\_pipe}”

rescue Errno::EAGAIN  
puts “ERROR: no input piped nor file name provided”  
display\_help  
end # end what kind of input  
end # end fill\_pipe

STDIN.close\_read doesn’t do the trick to reset things – ideas how I  
can have it both ways? Thanks! Andrew.

---

<div class="post-metadata">

**Author:** ![starmaerker](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/e9bcb4/32.png) [@starmaerker](https://www.ruby-forum.com/u/starmaerker)\
**Post date:** [November 25, 2008, 9:51am UTC](https://www.ruby-forum.com/t/pipe-in-cmd-line-text-but-then-reset-stdin-for-menu/154078/2 "2008-11-25T09:51:16Z")

</div>

Andrew Seidel wrote:

> I’m having trouble using the pipe to get the file contents and still be  
> able to use STDIN in a non-blocking way for a shell-style interactive  
> menu.

I think what you’re asking is: how can I write a program which does the  
same as this?

```
cat /usr/share/file/magic | less

```

(i.e. less reads its input from stdin, but can also read the terminal).

This is more a Unix question than a Ruby one. Probably the easiest way  
to find out will be to read the source code of ‘less’.

The less manpage directs you to [Less](http://www.greenwoodsoftware.com/less/)  
from where you can download the source tarball.

The relevant bit:

```
    /*
     * Try /dev/tty.
     * If that doesn't work, use file descriptor 2,
     * which in Unix is usually attached to the screen,
     * but also usually lets you read from the keyboard.
     */

```

#if OS2  
/\* The \_\_open() system call translates “/dev/tty” to “con”. \*/  
tty = \_\_open(“/dev/tty”, OPEN\_READ);  
#else  
tty = open(“/dev/tty”, OPEN\_READ);  
#endif  
if (tty \< 0)  
tty = 2;

That is: it opens /dev/tty for keyboard input, and falls back to fd 2 if  
that fails. In Ruby that would be something like

mystdin = IO.open(“/dev/tty”) rescue IO.for\_fd(2)

or if your user library can only talk to STDIN, then perhaps

STDIN.reopen(“/dev/tty”)

All untested.

---

<div class="post-metadata">

**Author:** ![starmaerker](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/e9bcb4/32.png) [@starmaerker](https://www.ruby-forum.com/u/starmaerker)\
**Post date:** [November 25, 2008, 10:26pm UTC](https://www.ruby-forum.com/t/pipe-in-cmd-line-text-but-then-reset-stdin-for-menu/154078/3 "2008-11-25T22:26:25Z")

</div>

Brian,  
Thanks! I’ll try some things out a let the forum know iff I produce  
something of interest. Cheers, Andrew.
