Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy: strings with embedded quotes don't execute as expected

Tags:

groovy

This is weird: using groovy strings to hold some command lines for execution, I find that sometimes if there are quote characters inside the string, the execution simply silently fails.

WTF? (Updated, see below.)

Here's my test program:

print " 1: " ; "grep nameserver /etc/resolv.conf".execute().text.eachLine {println it }          ; println ""
print " 2: " ; "grep 'nameserver' /etc/resolv.conf".execute().text.eachLine {println it }        ; println ""
print " 3: " ; """grep nameserver /etc/resolv.conf""".execute().text.eachLine {println it }      ; println ""
print " 4: " ; """grep "nameserver" /etc/resolv.conf""".execute().text.eachLine {println it }    ; println ""
print " 5: " ; """grep 'nameserver' /etc/resolv.conf""".execute().text.eachLine {println it }    ; println ""
print " 6: " ; "awk /nameserver/ /etc/resolv.conf".execute().text.eachLine{ println it }         ; println ""
print " 7: " ; "awk '/nameserver/' /etc/resolv.conf".execute().text.eachLine{ println it }       ; println ""
print " 8: " ; """awk "/nameserver/" /etc/resolv.conf""".execute().text.eachLine{ println it }   ; println ""
print " 9: " ; """awk '/nameserver/' /etc/resolv.conf""".execute().text.eachLine{ println it }   ; println ""
print "10: " ; """awk "/nameserver/{print \$2}" /etc/resolv.conf""".execute().text.eachLine{ println it }   ; println ""
return

Here's the results:

$ groovy weird.groovy 
 1: nameserver 10.3.0.101
nameserver 10.4.1.237
nameserver 10.2.1.34

 2: 
 3: nameserver 10.3.0.101
nameserver 10.4.1.237
nameserver 10.2.1.34

 4: 
 5: 
 6: nameserver 10.3.0.101
nameserver 10.4.1.237
nameserver 10.2.1.34

 7: 
 8: nameserver 10.3.0.101
nameserver 10.4.1.237
nameserver 10.2.1.34
domain lnx.copansys.com
search lnx.copansys.com tst.copansys.com copansys.com

 9: 
10: 

Update

Here's another example:

"bash -c echo Hello".execute().text.eachLine{ println it }
"bash -c echo 'Hello'".execute().text.eachLine{ println it }
"bash -c echo \'Hello\'".execute().text.eachLine{ println it }

Results:

groovy> "bash -c echo Hello".execute().text.eachLine{ println it } 
groovy> "bash -c echo 'Hello'".execute().text.eachLine{ println it } 
groovy> "bash -c echo \'Hello\'".execute().text.eachLine{ println it } 

'Hello!'

Observe that embedding a backslash-quoted ' doesn't seem to help.

like image 401
Charlie Martin Avatar asked Sep 01 '10 22:09

Charlie Martin


People also ask

How do you escape quotes in Groovy?

To escape a double quote, you can use the backslash character: "A double quote: \"".

Are strings mutable in Groovy?

String is an example of an immutable type. A String object always represents the same string. StringBuilder is an example of a mutable type. It has methods to delete parts of the string, insert or replace characters, etc.

How can a Groovy string be expressed?

Groovy offers a variety of ways to denote a String literal. Strings in Groovy can be enclosed in single quotes ('), double quotes (“), or triple quotes (“””). Further, a Groovy String enclosed by triple quotes may span multiple lines.


1 Answers

When you execute commands with String.execute(), they don't get parsed by a command shell. The quotes are passed through to the actual commands executed; in this case, grep and awk.

This is illustrated by replacing grep and awk with echo:

print " 1: " ; "echo something".execute().text.eachLine {println it }          ; println ""
print " 2: " ; "echo 'something'".execute().text.eachLine {println it }        ; println ""
print " 3: " ; """echo something""".execute().text.eachLine {println it }      ; println ""
print " 4: " ; """echo "something" """.execute().text.eachLine {println it }   ; println ""
print " 5: " ; """echo 'something'""".execute().text.eachLine {println it }    ; println ""

Which results in:

 1: something

 2: 'something'

 3: something

 4: "something"

 5: 'something'

A simple workaround is to build the command line as a list of strings:

["awk", 'BEGIN { print "hello" }'].execute().text

If you need finer control over the how the command is parsed, take a look at ProcessBuilder, the Java class String.execute() is built around.

like image 137
ataylor Avatar answered Nov 16 '22 03:11

ataylor