NAME Shell::Cmd - run shell commands with enhanced support SYNOPSIS use Shell::Cmd; $obj = new Shell::Cmd; DESCRIPTION A very common use of perl is to act as a wrapper around shell commands where perl is used to prepare the shell commands, execute them, and deal with the resulting output. Even where the bulk of the work is actually done in the perl script, creating small shell scripts within it to do some portion of the task is common. In the simplest form, running shell commands can be done very simply using the "system()" call, backticks, or several other ways, but I usually find myself wanting to do a bit (and sometimes a lot) more, especially when I am writing a long-term script that I want to be robust. In these cases, I frequently ended up writing a subroutine to run the shell command(s) for me with added functionality. This module is designed to take a list of shell commands and automatically turn them into a shell script (using only basic shell commands which are available in any bourne shell variation) which adds some common desirable functionality including: Handle STDOUT/STDERR Commonly, I want to treat STDOUT and STDERR in some way. I may want to keep one or both of them, or discard one or both of them, or merge them. Command echoing A common option I want to set is command echoing where the commands I run are echoed as they are run. I want to be able to easily turn this on or off (typically with a command line option in the calling script). Dry-run Another common option is to create a dry-run environment where the shell commands may be printed, but not actually run. Again, I want to be able to turn this on and off easily. Error trapping Even though I may combine a number of shell commands into a single script (so that it all runs in one shell), I still want to have built in error trapping at a per-command basis. I want to take a series of commands and know exactly which one failed. If I execute the commands one at a time, I can get that information, but typically, I want to combine multiple commands in a single script but still have that ability. I also want to be able to control what happens to commands that are listed after a failed command. I may want to ignore an error and continue to run the remaining commands. I may want to simply exit. Or I may want to echo, but not run the remaining commands so that I can see what didn't get completed. Shell environment I sometimes want to set up some environment for the script such as what directory it will be run in and what environment variables should be set in advance. Command alternates Sometimes, especially if you are running the script on multiple platforms, you may not know which command you should use. You can of course generate a platform specific script, but an alternative is to specify alternate commands. If ANY of those commands succeed, then that portion of the script succeeds. Command retrying Occasionally you have a command that may fail, but on retrying, it will succeed. This is especially true when some effect from a previous command takes some amount of time to actually go into effect. By allowing a certain number of retries, you can often work around this situation. Remote execution Sometimes you want to run the commands locally. Other times, you want to run it remotely using ssh. When running remotely, you may want to run the same script on multiple hosts. SSH handling When running on multiple hosts using SSH, sometimes you need to run the script serially (i.e. one host at a time), but other times, it would be nice to run it in parallel to speed up execution. When running in parallel, you should be able specify how many instances to run at at time. Quoting and special characters Since shell commands often have quotes, dollar signs, and other special characters, this module can handle that for you by properly escaping them as necessary. This module is designed to run multiple commands in a single shell, wrapping them in very simple, standard shell commands to automatically add all of this functionality. METHODS new $obj = new Shell::Cmd; This creates a new object containing commands. version $vers = $obj->version(); Returns the version of this module. cmd $err = $obj->cmd($cmd [,\%options], $cmd [,\%options], ...); This is used to add one or more commands to the list of commands that will be executed. Here, each $cmd is either a string containing a command, or a listref where each element in the list is a string containing a command. In the listref form, the list of commands are alternates to try until one succeeds, and the command only fails if all of the alternates fail. This might be used to specify different paths to an executable, or different executables that perform essentially the same function, but which might not all be available on all platforms. For example, if you wanted to run a command to get the contents of a web site, and you didn't know which of curl, wget, or lftp were available, you might use something like this: $err = $obj->cmd([ "wget $URL", "curl $URL", "lftp $URL"]); and in this case, it would try wget, and if that failed, it would try curl, and if that failed, it would try lftp. The command will only fail if all three alternates fail. Each command (or list of alternates) can have options passed in. These options apply only to this command (or list), and are described in the "PER-COMMAND OPTIONS" section below. All of the commands stored in $obj will be run in a single shell, so it is fine to gather information in one command and store it in a shell variable for use in a later command. Commands must not include a trailing semi-colon as these will interfere with I/O redirection, and will be added automatically as needed. An error is returned if any of the arguments are invalid. It should be noted that no attempt is made to see if the syntax of the shell command is correct. That is beyond the scope of this module. If only simple lists of commands are used, handling them is relatively straightforward, but trying to include commands that affect the flow of the script (such as "while...done", "if...else", and the like) then handling can be much more complicated. Refer to the "FLOW COMMANDS" section below. Defining functions is NOT supported. run $ret = $obj->run(); This prepares a shell script based on the commands and options entered and runs it as appropriate. The script is stored in a temporary file that can be set using the tmp_script option (refer to the "GLOBAL OPTIONS" section below). There are several different ways in which the commands can be run, and these are described in the options method below. The most important option is the mode option which determines the form of the script, and how it is run. If the mode is run, the method is called as: $err = $obj->run(); In this mode, the script is run, and output is sent directly to STDOUT and STDERR as appropriate for the options specified. In essence, this generates a script and runs it with the "system()" call. The error code returned is described below in the "ERROR CODES" section. In dry-run mode, the method is called as: $script = $obj->run(); In this mode, the commands are not actually executed. Instead, the script is built and returned. The form of the script is determined by the script option described below. In script mode, the method is called as: $err = $obj->run(); In this case, the output from the commands are kept for further analysis. The "$obj-"output(...)> method may then be used to examine the resulting output. The error codes are described in the "ERROR CODES" section below. ssh This behaves similar to the "run" method except it will run the commands on each host in @hosts using ssh. The return values for each mode are identical to the return methods from the "run" method except that for both the run mode and script mode, the output is returned as a hash where the keys are the hosts and the values are the value for that host. For example, in run mode, the call would be: %err = $obj->ssh(@hosts) In dry-run mode, the call is identical to the run method, and it will return the script that would be run on each host. $script = $obj->ssh(@hosts); Note that when running in parallel in run mode, the output that is printed to the terminal will be a mix of the output from each of the hosts the commands are being run on. output $ret = $obj->output(%options); @ret = $obj->output(%options); %ret = $obj->output(%options); This will return the output produced by running the commands in script mode depending on the options passed in. The %options argument is described below in the OUTPUT OPTIONS section. flush $obj->flush( [@opts] ); If @opts is not given, it removes all the data stored in the object, resetting it to a clean object. If @opts is given, you can clear specific parts of the object. Any of the following options can be given: commands : clears all commands and their options env : clears the environment opts : clears all options out : clears the output from running the command in B