简体   繁体   中英

Bad result from groovy's ProcessGroovyMethods (UNIXProcess)

While using Grails 2.4.5 org.codehaus.groovy.runtime.ProcessGroovyMethods on Ubuntu 14.04:

def command = "mysqldump -h${databaseProperties.host} -u'${databaseProperties.username}' -p'${databaseProperties.password}' ${databaseProperties.name} " + table
print command
def proc = command.execute()
def oneMinute = 60000
proc.waitForOrKill(oneMinute)
if(proc.exitValue()!=0){
    println "[[return code: ${proc.exitValue()}]]"
    println "[[stderr: ${proc.err.text}]]"
    return null
}else{
    return proc.in.text.readLines()
}

I've got

[[return code: 2]]
[[stderr: mysqldump: Got error: 1045: Access denied for user 'root'@'localhost' (using password: YES) when trying to connect]]

but when I copy-paste printlined command into my bash I receive proper dump. What is going on?


I've also tried:

  • changing mysqldump to full path: /usr/bin/mysqldump

  • sending arguments as a String array but with the same result.

  • sending command as a regular String to execute:

     "mysqldump -hlocalhost -u'root' -p'password' database table" 

it works in system bash, it doesn't as a ProcessGroovyMethod...

Update :

After thinking about this overnight, I'm (still) convinced that the problem is related to your password. Since it's really not a best practice to provide the password on the command line (mysqldump even warns you about this), I think you should change tactics by creating a login-path.

Use the following command to create a login path (this is a one-time step):

mysql_config_editor set --login-path=name --host=localhost --user=youruser --password

Then change the command you're attempting to execute from Groovy to this:

def command="mysqldump --login-path=name database table"

This will work around the issue you're seeing and is more secure.

Original answer :

I was able to replicate the problem. String.execute() doesn't use a command shell, and therefore the single quotes are getting passed to mysqldump as if they were part of your password.

Edit : After some further thought, I don't think Groovy's String.execute() is the way to go here, because of its unexpected handling of quotes. It's fine if your password doesn't include spaces, but this is likely to be brittle.

If you need more control, you should consider using ProcessBuilder :

ProcessBuilder pb = new ProcessBuilder("mysqldump", "-h${databaseProperties.host}", "-u${databaseProperties.username}", "-p${databaseProperties.password}", databaseProperties.name, table);
pb.inheritIO();
Process p = pb.start();

Edit : Further research, just tested this with a password that includes spaces. command.execute() doesn't handle this properly, but using the ProcessBuilder method works.

Here's another post explaining some of the unexpected behavior of the String.execute() method:

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

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