97

I'm using Grunt (task-based command line build tool for JavaScript projects) in my project. I've created a custom tag and I am wondering if it is possible to run a command into it.

To clarify, I'm trying to use Closure Templates and "the task" should call the jar file to pre-compile the Soy file to a javascript file.

I'm running this jar from command line, but I want to set it as a task.

Rob Evans
  • 6,750
  • 4
  • 39
  • 56
JuanO
  • 2,500
  • 3
  • 18
  • 20

6 Answers6

106

Alternatively you could load in grunt plugins to help this:

grunt-shell example:

shell: {
  make_directory: {
    command: 'mkdir test'
  }
}

or grunt-exec example:

exec: {
  remove_logs: {
    command: 'rm -f *.log'
  },
  list_files: {
    command: 'ls -l **',
    stdout: true
  },
  echo_grunt_version: {
    command: function(grunt) { return 'echo ' + grunt.version; },
    stdout: true
  }
}
papercowboy
  • 3,369
  • 2
  • 28
  • 32
  • 9
    Does anyone know if either of those two is usable on Windows? – Capaj Apr 25 '13 at 11:50
  • I could not immediately get `grunt-shell` to work with Windows+Cygwin but I had better luck with `grunt-exec`. – Nathan Mar 10 '14 at 18:44
  • 3
    Is there a way to use grunt-exec synchronously? It would be nice to chain commands together – funseiki May 13 '14 at 20:36
  • 1
    @funseiki just put the commands inside a batch or shell which calls the commands in you preferred order. Or you define task e.g. mycmds and write `"exec:cmd1", "exec:cmd2"` then you also have synchronously order. – Sebastian Aug 12 '14 at 09:18
37

Check out grunt.util.spawn:

grunt.util.spawn({
  cmd: 'rm',
  args: ['-rf', '/tmp'],
}, function done() {
  grunt.log.ok('/tmp deleted');
});
johnny 5
  • 19,893
  • 50
  • 121
  • 195
Nick Heiner
  • 119,074
  • 188
  • 476
  • 699
  • 5
    with `opts: {stdio: 'inherit'},` you can see the output of command – JuanPablo Jun 30 '14 at 13:09
  • 2
    Note: cmd param should be a string not an array. – RKI Oct 27 '15 at 14:19
  • 1
    This now requires the [`grunt-legacy-util`](https://github.com/gruntjs/grunt-legacy-util) plugin. It recommends using [`require('child_process').spawn()`](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options) instead. – J.D. Jul 21 '16 at 16:02
21

I've found a solution so I'd like to share with you.

I'm using grunt under node so, to call terminal commands you need to require 'child_process' module.

For example,

var myTerminal = require("child_process").exec,
    commandToBeExecuted = "sh myCommand.sh";

myTerminal(commandToBeExecuted, function(error, stdout, stderr) {
    if (!error) {
         //do something
    }
});
alex
  • 479,566
  • 201
  • 878
  • 984
JuanO
  • 2,500
  • 3
  • 18
  • 20
  • 12
    A better approach is to use a plugin (or write your own) to keep your grunt config as config and not code. grunt-shell & grunt-exec are two examples. – papercowboy Nov 01 '12 at 23:10
  • As you use ```sh``` before ```sh mayCommand.sh ``` I'm not sure it would work on windows – svassr Dec 16 '13 at 20:22
  • It won't work because it's bash scripting. I'm running under Unix OS's – JuanO Dec 17 '13 at 00:54
18

If you are using the latest grunt version (0.4.0rc7 at the time of this writing) both grunt-exec and grunt-shell fail (they don't seem to be updated to handle the latest grunt). On the other hand, child_process's exec is async, which is a hassle.

I ended up using Jake Trent's solution, and adding shelljs as a dev dependency on my project so I could just run tests easily and synchronously:

var shell = require('shelljs');

...

grunt.registerTask('jquery', "download jquery bundle", function() {
  shell.exec('wget http://jqueryui.com/download/jquery-ui-1.7.3.custom.zip');
});
kikito
  • 51,734
  • 32
  • 149
  • 189
  • 1
    fyi `grunt-shell` is working fine with `grunt v0.4.5` under Windows – fiat Aug 09 '15 at 03:39
  • I think using shelljs is a great solution because it enables your node app to access the shell, and it gives you finer control over it than the grunt addons alone. – Nick Steele Oct 03 '15 at 05:11
17

Guys are pointing child_process, but try to use execSync to see output..

grunt.registerTask('test', '', function () {
        var exec = require('child_process').execSync;
        var result = exec("phpunit -c phpunit.xml", { encoding: 'utf8' });
        grunt.log.writeln(result);
});
Ricardo Gladwell
  • 3,770
  • 4
  • 38
  • 59
Artjom Kurapov
  • 6,115
  • 4
  • 32
  • 42
2

For async shell commands working with Grunt 0.4.x use https://github.com/rma4ok/grunt-bg-shell.

Daniel Steigerwald
  • 1,075
  • 1
  • 9
  • 19