The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Rex::Commands::Run - Execute a remote command

DESCRIPTION

With this module you can run a command.

SYNOPSIS

 my $output = run 'ls -l';
 sudo 'id';

EXPORTED FUNCTIONS

run($command [, $callback], %options)

This function will execute the given $command and returns the output. In scalar context it returns the raw output as is, and in list context it returns the list of output lines. The exit value of the command is stored in the $? variable.

 run 'uptime';
 my $output       = run 'uptime';
 my @output_lines = run 'uptime';

It supports optional callbacks as subroutine reference, which will receive the command's output sent to STDOUT and STDERR.

 run 'uptime', sub {
   my ( $stdout, $stderr ) = @_;
   my $server = Rex::get_current_connection()->{server};
   say "[$server] $stdout\n";
 };

It also takes further options in a form of a hash. Supported options are:

cwd => $path

Sets the working directory of the executed command to $path.

only_if => $condition_command

Executes the command only if $condition_command returns success.

unless => $condition_command

Executes the command if $condition_command returns failure.

only_notified => TRUE

Queues the command to be executed later upon notification.

env => { var1 => $value1, ..., varN => $valueN }

Sets environment variables for the given command.

timeout => value

Sets the timeout for the command to be run.

auto_die => TRUE

Die if the command returns with an exit code indicating failure. It can be set globally via the exec_autodie feature flag.

command => $command_to_run

If present, Rex will execute $command_to_run, and treat the first arugment as an identifier for the given run() block (e.g. to be triggered with notify).

creates => $file_to_create

Tries to create $file_to_create upon execution, and skips execution if the file already exists.

continuous_read => $callback

Calls $callback subroutine reference for each line of the command's output, passing the line as an argument.

end_if_matched => qr{$pattern}

End execution early as soon as $pattern is detected in the command's output.

Examples:

If you only want to run a command if another command succeeds or fails, use the only_if or unless options.

 run 'some-command',
   only_if => 'pgrep httpd'; # only run if httpd is running

 run 'some-other-command',
   unless => 'pgrep httpd'; # only run if httpd is _not_ running

If you want to set custom environment variables you can do it like this:

 run 'my_command',
   env => {
     env_var_1 => 'the value for 1',
     env_var_2 => 'the value for 2',
   };

If you want to end the command upon receiving a certain output:

 run 'my_command',
   end_if_matched => qr{$pattern};

run($command, $arguments, %options)

This form will execute $command with the given $arguments pass as an array reference. All arguments will be quoted by Rex with Net::OpenSSH::ShellQuoter-quoter()> according to the managed host's shell.

 run 'ls', [ '-l', '-t', '-r', '-a' ];
 run 'ls', [ '/tmp', '-l' ], auto_die => TRUE;

run($command_description, command => $command, %options)

If you only want to run a command in certain cases, you can queue the command and notify it to trigger its execution.

 run 'extract-something',
   command       => 'tar -C /foo -xzf /tmp/foo.tgz',
   only_notified => TRUE;

 # some code ...

 notify 'run', 'extract-something'; # now the command gets executed

can_run($command)

This function checks if a command is available in the path. It accepts a list of commands, and returns the full path to the first command found.

 task 'uptime', sub {
   if ( my $cmd = can_run( 'uptime', 'downtime' ) ) {
     say run $cmd;
   }
 };

sudo

Run a single command, a code block, or all commands with sudo. You need perl to be available on the remote systems to use sudo.

Depending on your remote sudo configuration, you may need to define a sudo password with sudo_password first:

 sudo_password 'my_sudo_password'; # hardcoding

Or alternatively, since Rexfile is plain perl, you can read the password from terminal at the start:

 use Term::ReadKey;
 
 print 'I need sudo password: ';
 ReadMode('noecho');
 sudo_password ReadLine(0);
 ReadMode('restore');

Similarly, it is also possible to read it from a secret file, database, etc.

You can turn sudo on globally with:

 sudo TRUE; # run _everything_ with sudo

To run only a specific command with sudo, use :

 say sudo 'id';                # passing a remote command directly
 say sudo { command => 'id' }; # passing anonymous hashref
 
 say sudo { command => 'id', user => 'different' }; # run a single command with sudo as different user
 

To run multiple commands with sudo, either use an anonymous code reference directly:

 sudo sub {
     service 'nginx' => 'restart';
     say run 'id';
 };

or pass it via command (optionally along a different user):

 sudo {
     command => sub {
         say run 'id';
         say run 'pwd', cwd => '/home/different';
     },
     user => 'different',
 };

Note that some users receive the error sudo: sorry, you must have a tty to run sudo. In this case you have to disable requiretty for this user. You can do this in your sudoers file with the following code:

   Defaults:$username !requiretty