Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

piping and redirection

27 views
Skip to first unread message

Will Parsons

unread,
May 27, 2012, 9:10:09 PM5/27/12
to
Hi,

I wrote a ruby program that prints out more than a screen's worth of
data to stdout, so I got into the habit of routinely invoking it as:

progname | more

Since I was doing this all the time, I thought it would be an
improvement to incorporate the paging into a script, so I re-wrote the
ruby script in the form:

-----------
#!/bin/sh
ruby <<'EOF' | ${PAGER:-more}

# ruby commands here

EOF
-----------

This works fine unless I want to pipe to an alternative program, e.g.:

progname | head -20

This "works", but I get an unpleasant error message, such as:

-:16:in `write': Broken pipe (Errno::EPIPE)
from -:16:in `puts'
from -:16
from -:10:in `each'
from -:10

So, I was wondering if it is possible for the script to detect if
stdout has been redirected and avoid doing its own piping to "more" if
it has, or is this something that really can't be detected at the
shell level?

--
Will

Janis Papanagnou

unread,
May 27, 2012, 9:39:27 PM5/27/12
to
In Kornshell I use the test operator

[[ -t 1 ]] && echo TTY
[[ ! -t 1 ]] && echo no TTY

This option -t is also defined by POSIX for the test(1) command.

Janis

Martin Vaeth

unread,
May 28, 2012, 7:30:51 AM5/28/12
to
Janis Papanagnou <janis_pa...@hotmail.com> wrote:
>>
>> progname | more
>>
>> Since I was doing this all the time,

Maybe you should think about using zsh as interactive shell
which has inline aliases: alias -g M='|more'
progname M

> This option -t is also defined by POSIX for the test(1) command.

Therefore, "test -t 1" is probably more compatible.

Will Parsons

unread,
May 28, 2012, 11:32:39 AM5/28/12
to
Janis Papanagnou wrote:
> On 28.05.2012 03:10, Will Parsons wrote:
>> Hi,
>>
>> I wrote a ruby program that prints out more than a screen's worth of
>> data to stdout, so I got into the habit of routinely invoking it as:
>>
>> progname | more
>>
>> Since I was doing this all the time, I thought it would be an
>> improvement to incorporate the paging into a script, so I re-wrote the
>> ruby script in the form:
>>
>> -----------
>> #!/bin/sh
>> ruby <<'EOF' | ${PAGER:-more}
>>
>> # ruby commands here
>>
>> EOF
>> -----------
>>
>> This works fine unless I want to pipe to an alternative program, e.g.:
>>
>> progname | head -20
>>
>> This "works", but I get an unpleasant error message, such as:
>>
>> -:16:in `write': Broken pipe (Errno::EPIPE)
>>
>> So, I was wondering if it is possible for the script to detect if
>> stdout has been redirected and avoid doing its own piping to "more" if
>> it has, or is this something that really can't be detected at the
>> shell level?
>>
>
> In Kornshell I use the test operator
>
> [[ -t 1 ]] && echo TTY
> [[ ! -t 1 ]] && echo no TTY
>
> This option -t is also defined by POSIX for the test(1) command.

Thanks - I wasn't aware of the test -t option. I'll use that since I
prefer to make my shell scripts as portable as possible. Now I just
have to figure out how to use that to determine whether to pipe
without having to replicate the body of the code in an if/then/else/fi
construction.

--
Will

Will Parsons

unread,
May 28, 2012, 11:35:33 AM5/28/12
to
Martin Vaeth wrote:
> Janis Papanagnou <janis_pa...@hotmail.com> wrote:
>>>
>>> progname | more
>>>
>>> Since I was doing this all the time,
>
> Maybe you should think about using zsh as interactive shell
> which has inline aliases: alias -g M='|more'
> progname M

Thanks, but the question was really about how to do that inside a
shell script.

>> This option -t is also defined by POSIX for the test(1) command.
>
> Therefore, "test -t 1" is probably more compatible.

Yup, I'll be using that.

--
Will

Barry Margolin

unread,
May 28, 2012, 12:55:58 PM5/28/12
to
In article <slrnjs76kn...@anukis.local>,
Will Parsons <oud...@nodomain.invalid> wrote:

> Janis Papanagnou wrote:
> >> So, I was wondering if it is possible for the script to detect if
> >> stdout has been redirected and avoid doing its own piping to "more" if
> >> it has, or is this something that really can't be detected at the
> >> shell level?
> >>
> >
> > In Kornshell I use the test operator
> >
> > [[ -t 1 ]] && echo TTY
> > [[ ! -t 1 ]] && echo no TTY
> >
> > This option -t is also defined by POSIX for the test(1) command.
>
> Thanks - I wasn't aware of the test -t option. I'll use that since I
> prefer to make my shell scripts as portable as possible. Now I just
> have to figure out how to use that to determine whether to pipe
> without having to replicate the body of the code in an if/then/else/fi
> construction.

There's two common ways. One is to put the body of the code in a
function, and then do:

if [ -t 1 ]
then func | less
else func
fi

The other is to use exec:

[ ! -t 1 ] && exec | less
... rest of script

--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***

Will Parsons

unread,
May 28, 2012, 4:37:23 PM5/28/12
to
Barry Margolin wrote:
> In article <slrnjs76kn...@anukis.local>,
> Will Parsons <oud...@nodomain.invalid> wrote:
>> Thanks - I wasn't aware of the test -t option. I'll use that since I
>> prefer to make my shell scripts as portable as possible. Now I just
>> have to figure out how to use that to determine whether to pipe
>> without having to replicate the body of the code in an if/then/else/fi
>> construction.
>
> There's two common ways. One is to put the body of the code in a
> function, and then do:
>
> if [ -t 1 ]
> then func | less
> else func
> fi
>
> The other is to use exec:
>
> [ ! -t 1 ] && exec | less
> ... rest of script

Thanks for the tips. Unfortunately, for reasons I don't understand,
it still doesn't give me the result I'm looking for, i.e.,
"progname | head" still results in an EPIPE error when restructured as:

#!/bin/sh

report()
{
ruby <<'EOF'
...
EOF
}

if [ -t 1 ]
then
echo TTY
report | ${PAGER:-more}
else
echo NTTY
report
fi

(The "echo NTTY" is printed showing that test -t is doing its thing.)
I think I may be dealing with an issue of how ruby is invoked inside
the script, however, since if I replace "ruby" with e.g. "cat" the
EPIPE error is not produced. Anyway, even if don't succeed in solving
this in the shell, thanks to you and Janis for your replies.

--
Will

Barry Margolin

unread,
May 28, 2012, 5:21:00 PM5/28/12
to
In article <slrnjs7og3...@anukis.local>,
This error has nothing to do with whether the pager is being used.

When head exits, the read end of the pipe is closed. There are two ways
that a program can deal with writing to a closed pipe. By default, the
OS sends it a SIGPIPE signal, and this causes the program to exit.
Normally, the shell prints a message when a program exits due to a
signal, but this situation is so common and normal that most shells
filter this particular one out.

The other option is to ignore the signal. In this case, the write()
call returns an EPIPE error. Ruby apparently does this, and then
reports the error. See this Stack Overflow thread for a way to program
your ruby script so that it handles the error without a message:

http://stackoverflow.com/questions/2845507/how-do-you-pipe-output-from-a-
ruby-script-to-head-without-getting-a-broken-pip

Will Parsons

unread,
May 28, 2012, 6:13:44 PM5/28/12
to
You're absolutely correct, and now that I understand better what's
going on, I can easily accommodate the situation. Thanks again for
your help!

--
Will

MJ

unread,
Jun 17, 2012, 12:26:11 AM6/17/12
to
On Mon, 28 May 2012 01:10:09 +0000, Will Parsons wrote in
slrnjs5k3h...@anukis.local :

..
> Since I was doing this all the time, I thought it would be an
> improvement to incorporate the paging into a script, so I re-wrote the
> ruby script in the form:
>
> -----------
> #!/bin/sh
> ruby <<'EOF' | ${PAGER:-more}
>
> # ruby commands here
>
> EOF

Why invoke the overhead of a Bourne shell just to interpret Ruby commands?

#!/usr/bin/env ruby
# ruby commands here

Will Parsons

unread,
Jun 19, 2012, 4:57:15 PM6/19/12
to
Originally this *was* a ruby script - I converted it to a shell script
so I could incorporate the paging. No doubt there is way to do it in
pure ruby, but using the shell seemed easier, and hence my question.
Overhead is irrelevant.

--
Will
0 new messages