简体   繁体   中英

How to read standard input from a Bash heredoc within a Groovy script

I'm trying to make a Groovy script read standard input, so I can call it from a Bash script with a heredoc, but I get a java.lang.NullPointerException: Cannot invoke method readLine() on null object exception.

Here's a cut-down Groovy script echo.groovy :

#!/usr/bin/env groovy
for (;;)
{
    String line = System.console().readLine()
    if (line == null)
        break
    println(">>> $line")
}

Here's the equivalent Ruby script echo.rb :

#!/usr/bin/env ruby
ARGF.each do |line|
  puts ">>> #{line}"
end

If I call these from a Bash shell, everything works as expected:

$ ./echo.rb 
one
>>> one
two
>>> two
three
>>> three
^C
$ ./echo.groovy 
one
>>> one
two
>>> two
three
>>> three
^C

This is the Bash script heredoc.sh using heredocs:

echo 'Calling echo.rb'
./echo.rb <<EOF
one
two
three
EOF
echo 'Calling echo.groovy'
./echo.groovy <<EOF
one
two
three
EOF

This is what happens when I run it:

$ ./heredoc.sh 
Calling echo.rb
>>> one
>>> two
>>> three
Calling echo.groovy
Caught: java.lang.NullPointerException: Cannot invoke method readLine() on null object
java.lang.NullPointerException: Cannot invoke method readLine() on null object
        at echo.run(echo.groovy:4)

Any ideas?

UPDATE

On Etan's advice, I changed echo.groovy to the following:

#!/usr/bin/env groovy
Reader reader = new BufferedReader(new InputStreamReader(System.in))
for (;;)
{
    String line = reader.readLine()
    if (line == null)
        break
    println(">>> $line")
}

It now works with heredocs:

$ ./heredoc.sh 
Calling echo.rb
>>> one
>>> two
>>> three
Calling echo.groovy
>>> one
>>> two
>>> three

Thanks Etan. If you'd like to post a formal answer, I'll upvote it.

As Etan says, you need to read from System.in I think this will get the response you are after

#!/usr/bin/env groovy
System.in.withReader { r ->
    r.eachLine { line ->
        println ">>> $line"
    }
}

Thought it's not exactly the same as the Ruby version, as ARGF will return arguments if any were passed

As an alternative to Etan's answer, a Groovier approach is the withReader method, which handles the cleanup of the reader afterwards, and the BufferedReader's eachLine method, which handles the infinite looping.

#!/usr/bin/env groovy

System.in.withReader { console ->
    console.eachLine { line ->
        println ">>> $line"
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM