Creating Custom Drush Commands

Creating a new drush command is very easy. There are four simple steps.

  1. Create a command file called COMMANDFILE.drush.inc
  2. Implement the function COMMANDFILE_drush_help(). Optional.
  3. Implement the function COMMANDFILE_drush_command()
  4. Implement the functions that your commands will call. These will usually be named drush_COMMANDFILE_COMMANDNAME().

For an example drush command, see examples/sandwich.drush.inc. The steps for implementing your command are explained in more detail below.

Create COMMANDFILE.drush.inc

The name of your drush command is very important. It must end in ".drush.inc" to be recognized as a drush command. The part of the filename that comes before the ".drush.inc" becomes the name of the commandfile. Your commandfile name is used by drush to compose the names of the functions it will call, so choose wisely.

The example drush command, 'make-me-a-sandwich', is stored in the 'sandwich' commandfile, 'sandwich.drush.inc'.

Drush searches for commandfiles in the following locations:

Note that modules in the current Drupal installation will only be considered if drush has bootstrapped to at least the DRUSH_BOOSTRAP_SITE level. Usually, when working with a Drupal site, drush will bootstrap to DRUSH_BOOTSTRAP_FULL; in this case, only the drush commandfiles in enabled modules will be considered eligible for loading. If a drush only bootstraps to DRUSH_BOOTSTRAP_SITE, though, then all drush commandfiles will be considered, whether the module is enabled or not. See `drush topic docs-bootstrap` for more information on bootstrapping.

Additionally, drush commandfiles may optionally define a function COMMANDFILE_drush_load() in the file COMMANDFILE.drush.load.inc. If this function returns FALSE, then the commandfile will not be loaded.

Implement COMMANDFILE_drush_help()

The drush_help hook is an optional place to describe a command in long form. If the command only requires a brief description, use the description key in COMMANDFILE_drush_command(). The drush_help hook for the 'sandwich' commandfile looks like this:

        function sandwich_drush_help($section) {
          switch ($section) {
            case 'drush:make-me-a-sandwich':
              return dt("... brief help summary goes here ...");
          }
        }

Note that the command name is prepended with 'drush:' in the drush_help hook. Your commandfile may implement multiple commands; to do so, just add more 'case' statements to the switch, one for each command.

Implement COMMANDFILE_drush_command()

The drush_command hook is the most important part of the commandfile. It returns an array of items that define how your commands should be called, and how they work. Drush commands are very similar to the Drupal menu system. The elements that can appear in a drush command definition are shown below.

The 'sandwich' drush_command hook looks like this:

        function sandwich_drush_command() {
          $items = array();

          $items['make-me-a-sandwich'] = array(
            'description' => "Makes a delicious sandwich.",
            'arguments' => array(
              'filling' => 'The type of the sandwich (turkey, cheese, etc.)',
            ),
            'options' => array(
              'spreads' => 'Comma delimited list of spreads (e.g. mayonnaise, mustard)',
            ),
            'examples' => array(
              'drush mmas turkey --spreads=ketchup,mustard' => 'Make a terrible-tasting sandwich that is lacking in pickles.',
            ),
            'aliases' => array('mmas'),
            'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, // No bootstrap at all.
          );

          return $items;
        }

Most of the items in the 'make-me-a-sandwich' command definition have no effect on execution, and are used only by `drush help`. The exceptions are 'aliases' (described above) and 'bootstrap'. As previously mentioned, `drush topic docs-bootstrap` explains the drush bootstrapping process in detail.

Implement drush_COMMANDFILE_COMMANDNAME()

The 'make-me-a-sandwich' command in sandwich.drush.inc is defined as follows:

	function drush_sandwich_make_me_a_sandwich($filling = 'ascii') {
	  ... implementation here ...
        }

If a user runs `drush make-me-a-sandwich` with no command line arguments, then drush will call drush_sandwich_make_me_a_sandwich() with no function parameters; in this case, $filling will take on the provided default value, 'ascii'. (If there is no default value provided, then the variable will be NULL, and a warning will be printed.) Running `drush make-me-a-sandwich ham` will cause drush to call drush_sandwich_make_me_a_sandwich('ham'). In the same way, commands that take two command line arguments can simply define two functional parameters, and a command that takes a variable number of command line arguments can use the standard php function func_get_args() to get them all in an array for easy processing.

Note that drush will actually call a sequence of functions before and after your drush command function. One of these hooks is the "validate" hook. The 'sandwich' commandfile provides a validate hook for the 'make-me-a-sandwich' command:

        function drush_sandwich_make_me_a_sandwich_validate() {
          $name = posix_getpwuid(posix_geteuid());
          if ($name['name'] !== 'root') {
            return drush_set_error('MAKE_IT_YOUSELF', dt('What? Make your own sandwich.'));
          }
        }

The validate function should call drush_set_error and return its result if the command cannot be validated for some reason. See `drush topic docs-policy` for more information on defining policy functions with validate hooks, and `drush topic docs-api` for information on how the command hook process works. Also, the list of defined drush error codes can be found in `drush topic docs-errorcodes`.