31

In my gradle file I defined the following task:

task text_example <<
{
   //?!? commandLine ''
   println 'Fam Flinstone'
}

I want to put inside this task some commands line. How can I do that ?

I'm using a library to automatically publish in google play. My project is based on Product Flavors and I need to pass in terminal command line by command line for every and each one of my flavors. So I want to pass all commands line in test_example task.

Opal
  • 81,889
  • 28
  • 189
  • 210
Corneliu
  • 421
  • 1
  • 6
  • 12

1 Answers1

61

You basically have two major convenient options:

  1. Use Gradle Exec task type

     task fooExec(type: Exec) {
         workingDir "${buildDir}/foo"
         commandLine 'echo', 'Hello world!'
         doLast {
             println "Executed!"
         }
     }
    
  2. Use Gradle Project.exec method

     task execFoo {
         doLast {
             exec {
                 workingDir "${buildDir}/foo"
                 executable 'echo'
                 args 'Hello world!'
             }
             println "Executed!"
         }
     }
    

In both cases inside the closure you can specify execution parameters using methods of ExecSpec. Standard output and error output from the executed commands will be redirected to stdout and stderr of the gradle process.

Edit @2022-07-07

There's an important caveat mentioned in the comments below: Gradle's exec does not evaluate a command line like a shell (e.g. Bash on Linux or CMD on Windows) would, it simply executes specified executable with the provided arguments.

This has some hidden consequences that one needs to keep in mind:

  1. To execute a 'command', one needs to specify a valid existing executable file.

    The most common case when this comes up is when trying to use 'commands' that are implemented on a specific OS by a shell and do not have an available implementation in a form of an executable file (e.g. echo and similar commands on Windows).

  2. There are no 'fancy' features supported by modern shells like streams redirects and similar (although you can still redirect stdout of one process to stdin of another using two separate exec invocations with custom IO configuration).

  3. User-defined aliases (e.g. defined in ~/.bsahrc) are not available.

FIY: do not actually do it!

The 'common' work around to 'easily' get a modern shell's functionality inside Gradle would be to actually run a shell process and provide the command line as its argument, e.g. if using Bash:

task shellExec(type: Exec) {
    workingDir "${buildDir}/foo"
    commandLine 'bash', '-c', "echo 'Hello world!'"
}

However, this approach instantly binds the build script to a particular platform making it inoperable on platforms that do not have that particular shell (e.g. above example would not work on Windows).

Andrei LED
  • 2,560
  • 17
  • 21
  • 1
    Does not work for newer Gradle. Need to use `doLast { }` closure instead of `<<` – Michał Dobi Dobrzański Jun 08 '21 at 12:33
  • Good catch! They deprecated `Taks.leftShift` in favor of `Taks.doLast` in 3.2. – Andrei LED Jun 10 '21 at 01:48
  • 1
    Updated my answer to be compatible with recent Gradle versions. – Andrei LED Jun 10 '21 at 02:09
  • 1
    Comment for Windows - using exec it's like running executable. So to run command line programs like echo you need: `exec { executable = "cmd" args = listOf("/C", "echo Hello World") }` – AndrzejPw Jul 05 '22 at 10:27
  • Good point! Although, I must add that the "_using exec it's like running executable_" statement is true for all OSes: `exec` does **not** evaluate a command line like a shell (e.g. Bash or Windows' CMD) would, it simply executes specified executable with the provided arguments. – Andrei LED Jul 08 '22 at 02:04
  • The reason the above samples work on *nix and do not work on Windows is because *nix systems have basic shell commands such as `echo` available as actual executable files. – Andrei LED Jul 08 '22 at 02:06