найти: отсутствует аргумент для `-exec', работающего в построителе процессов Java

Я пытаюсь запустить команду find внутри консоли сценария Jenkins (https://jenkins-ci.org), которая позволяет запускать groovy-скрипты из веб-интерфейса.

Мой код:

ProcessBuilder pb = new ProcessBuilder();
pb.directory(new File("/var/lib/jenkins/jobs/myJob");
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
command = 'find . -name build.xml -exec echo \"{}\" \\;'
println(command)
pb.command(command.split(" "));
pb.start().waitFor();

Веб-интерфейс отобразит результат println:

find . -name build.xml -exec echo "{}" \;

В то время как журнал jenkins (/var/log/jenkins/jenkins.log) регистрирует следующую ошибку:

find: missing argument to `-exec'

Однако, если я запускаю ту же команду, выведенную в веб-интерфейсе (find . -name build.xml -exec echo "{}" \;), через оболочку, я не получаю такой ошибки.

Кроме того, если я заменю \; на +, команда сработает!

Так что что-то не так с processBuilder и \\;, передаваемым в качестве аргумента командной строки.


person Dan Alvizu    schedule 28.10.2015    source источник


Ответы (2)


Проблема с ошибкой с \; заключается в том, что вы смешиваете экранирование/цитирование оболочки с простой передачей параметров функций exec.

Поставьте \ перед ; и все заработает. ; нужен \ только в оболочке, так как там он используется для разделения команд. То же самое касается цитирования {} - при передаче параметров функциям в стиле exec* не требуется цитирование/экранирование в стиле оболочки, поскольку ни одна оболочка не интерпретирует это (если, конечно, вы не запустите sh -c):

def command = 'find . -name build.xml -exec echo {} ;' // XXX
new ProcessBuilder()
    .directory(new File("/tmp"))
    .inheritIO()
    .command(command.split(" ")) // everything is just a list of strings
    .start()

И это в основном то же самое в groovy:

("/tmp" as File).eachFileRecurse{
    if (it.name=="build.xml") {
        println it
    }
}
person cfrick    schedule 28.10.2015
comment
всегда лучше использовать List в качестве аргумента команды. Я имею в виду любые разбиения, особенно если могут быть переданы аргументы времени выполнения. Однако +1. - person Opal; 28.10.2015
comment
да, я тоже не люблю развод. это работает только здесь, потому что в аргументах нет пробелов. - person cfrick; 28.10.2015

Не могли бы вы заменить все вышеперечисленное на:

String output = ['bash', '-c', 'find . -name "*.xml" -exec echo "{}" \\;']
    .execute(null, new File('/tmp')).text
person tim_yates    schedule 28.10.2015
comment
зачем заморачиваться с башкой? ['find', '/tmp', '-name', '*.xml', '-exec', 'echo', '{}', ';'].execute().text. - person cfrick; 28.10.2015
comment
Потрясающе, спасибо! Это приемлемая замена тому, чем я хочу заниматься. Ваш ответ также побудил меня узнать больше о groovy, чтобы делать то, что я действительно хотел сделать с помощью командной строки: найти файлы и заменить их на sed, но groovy предоставляет отличные API-интерфейсы ввода-вывода: groovy-lang.org/groovy-dev-kit.html#_working_with_io Тем не менее я хотел бы чтобы узнать, почему ProcessBuilder не может пройти \;, я не могу найти причину этого - person Dan Alvizu; 28.10.2015