Search code examples
rubycommand-line-interface

Discrepancy in Ruby CLI Option `-p` Behavior with and without Pipe


I'm observing different behaviors with the Ruby command-line option -p depending on whether it's used with or without a pipe. Here are the two scenarios:

Without Pipe:

  • When I run ruby -pe 'puts "You said #{$_}", it seems to just output the input as it is after what puts prints.

With Pipe:

  • However, using a pipe as in echo "hello world" | ruby -pe '$_.upcase! results in the expected transformation, printing an upcased "HELLO WORLD".

Can someone explain why there's a difference in behavior between these two scenarios? Is the -p option interacting differently with the input in each case?

FYI. The results are below.

$ echo "hello world" | ruby -pe '$_.upcase!'
HELLO WORLD
$ ruby -pe 'puts "You said #{$_}"'
1
You said 1
1
...

Solution

  • The -p flag, according to the ruby(1) man page, will "print the value of variable $_ at the each end of the loop.". In your example with the pipe, this is working as you expect: using upcase! will replace the value of $_ and Ruby will print it out afterwards.

    However, in your example without a pipe, you're using puts to explicitely print out a string, which happens in addition to the -p behaviour. Using the first example with and without a pipe works the same way:

    $ ruby -pe '$_.upcase!'
    aa
    AA
    $ echo "aa" | ruby -pe '$_.upcase!'
    AA
    

    You can also use the -n flag, which does the same as -p but won't automatically print out anything. For example:

    $ ruby -ne 'puts "You said #{$_}"'
    aa
    You said aa
    bb
    You said bb
    cc
    You said cc