NAME

Footprintless::Command - A factory for building common commands

VERSION

version 1.20

SYNOPSIS

use Footprintless::Command qw(command batch_command mkdir_command pipe_command rm_command sed_command);
my $command = command( 'echo' ); # echo

# ssh foo "echo"
$command = command( 'echo', command_options( hostname=>'foo' ) ); 

# ssh bar@foo "echo"
$command = command( 'echo', command_options( username=>'bar',hostname=>'foo' ) ); 

# plink -l bar foo "echo"
$command = command( 'echo', command_options( username=>'bar',hostname=>'foo',ssh=>'plink' ) ); 

# cd foo;cd bar
$command = batch_command( 'cd foo', 'cd bar' ); 

# ssh baz "cd foo;cd bar"
$command = batch_command( 'cd foo', 'cd bar', command_options( hostname=>'baz' ) ); 

# ssh baz "bash -c \"sudo cd foo;sudo cd bar\""
$command = batch_command( 'cd foo', 'cd bar', {subshell => 'bash -c' }, command_options( hostname=>'baz',sudo_username=>'' ) ); 

# ssh baz "mkdir -p \"foo\" \"bar\""
$command = mkdir_command( 'foo', 'bar', command_options( hostname=>'baz' ) ); 

# cat abc|ssh baz "dd of=def"
$command = pipe_command( 
        'cat abc', 
        command( 'dd of=def', command_options( hostname=>'baz' ) ) 
    ); 

# ssh fred@baz "sudo -u joe rm -rf \"foo\" \"bar\""
$command = rm_command( 'foo', 'bar', command_options( username=>'fred',hostname=>'baz',sudo_username=>'joe' ) ); 

# sed -e 's/foo/bar/'
$command = sed_command( 's/foo/bar/' ); 


# curl http://www.google.com|sed -e \'s/google/gaggle/g\'|ssh fred@baz "sudo -u joe dd of=\"/tmp/gaggle.com\"";ssh fred@baz "sudo -u joe rm -rf \"/tmp/google.com\"";
my $command_options = command_options( username=>'fred',hostname=>'baz',sudo_username=>'joe' );
$command = batch_command(
        pipe_command( 
            'curl http://www.google.com',
            sed_command( {replace_map=>{google=>'gaggle'}} ),
            command( 'dd of="/tmp/gaggle.com"', $command_options )
        ),
        rm_command( '/tmp/google.com', $command_options )
    );

DESCRIPTION

The subroutines exported by this module can build shell command strings that can be executed by IPC::Open3::Callback, Footprintless::CommandRunner, ``, system(), or even plain old open 1, 2, or 3. There is not much point to shelling out for commands locally as there is almost certainly a perl function/library capable of doing whatever you need in perl code. However, If you are designing a footprintless agent that will run commands on remote machines using existing tools (gnu/powershell/bash...) these utilities can be very helpful. All functions in this module can take a command_options hash defining who/where/how to run the command.

OPTIONS

FUNCTIONS

batch_command($command1, $command2, ..., $commandN, [\%batch_options], [$command_options])

This will join all the commands with a ; and apply the supplied command_options to the result. The supported batch_options are:

subshell

The subshell to run the commands under, must end with -c. (ex: 'bash -c')

command($command, [$command_options])

This wraps the supplied command with all the destination options. If no options are supplied, $command is returned.

command_options(%options)

Returns a command_options object to be supplied to other commands. All commands can be supplied with command_options. command_options control who/where/how to run the command. The supported options are:

ssh

The ssh command to use, defaults to ssh. You can use this to specify other commands like plink for windows or an implementation of ssh that is not in your path.

sudo_command

The actual sudo command. Most likely you will want to leave this undefined and let sudo be found in your $PATH. However, if for some reason you need to use a different version (ex: /usr/depot/bin/sudo, then this provides that option.

sudo_username

Prefixes your command thusly: sudo -u $sudo_username $command. If combined with a remote hostname, the sudo will be executed on the remote system. For example: ssh $hostname "sudo -u $sudo_user \"$command\"".

username

The username to ssh with. If using ssh, this will result in, ssh $username@$hostname but if using plink it will result in plink -l $username $hostname.

hostname

The hostname/IP of the server to run this command on. If localhost, and no username is specified, the command will not be wrapped in ssh

cp_command($source_path, [$source_command_options], $destination_path, [$destination_command_options], %cp_options)

This generates a command for copying files or directories from a source to a destination. Both source and destination have optional command_options, and the cp_command itself has the following options:

archive

If specified and set to 'zip', then zip will be used to archive the source before sending it to the destination. Otherwise, tar will be used. Note, that if file => 1 then this is ignored.

compress

If supplied and true, then the source data will be compressed before sending to the destination where it will be uncompressed before writing out. Note, that if you use archive => 'zip' then this is ignored as zip implies compression.

file

If supplied and true, then this is a file copy, otherwise it is a directory copy.

status

If supplied, a status indicator will be printed to STDERR. This option uses the unix pv command which is typically not installed by default. Also, this option only works with archive set to tar (the default), and file set to false (the default).

mkdir_command($path1, $path2, ..., $pathN, [$command_options])

Results in mkdir -p $path1 $path2 ... $pathN with the command_options applied.

pipe_command($command1, $command2, ..., $commandN, [$command_options])

Identical to batch_command except uses \| to separate the commands instead of ;.

rm_command($path1, $path2, ..., $pathN, [$command_options])

Results in rm -rf $path1 $path2 ... $pathN with the command_options applied. This is a VERY dangerous command and should be used with care.

sed_command($expression1, $expression2, ..., $expressionN, [$command_options])

Constructs a sed command

files

An arrayref of files to apply the sed expressions to. For use when not piping from another command.

in_place

If specified, the -i option will be supplied to sed thus modifying the file argument in place. Not useful for piping commands together, but can be useful if you copy a file to a temp directory, modify it in place, then transfer the file and delete the temp directory. It would be more secure to follow this approach when using sed to fill in passwords in config files. For example, if you wanted to use sed substitions to set passwords in a config file template and then transfer that config file to a remote server:

/my/config/passwords.cfg

app1.username=foo
app1.password=##APP1_PASSWORD##
app2.username=bar
app2.password=##APP2_PASSWORD##

deploy_passwords.pl

use Footprintless::Command qw(batch_command command pipe_command sed_command);
use Footprintless::CommandRunner;
use File::Temp;

my $temp_dir = File::Temp->newdir();
my $temp_script_file = File::Temp->new();
Footprintless::CommandRunner->new()->run_or_die(
    batch_command( 
        "cp /my/config/passwords.cfg $temp_dir->filename()/passwords.cfg",
        sed_command( 
            "s/##APP1_PASSWORD##/set4app1/g",
            "s/##APP2_PASSWORD##/set4app2/g", 
            {
                in_place=>1,
                temp_script_file=>$temp_script_file,
                files=>[$temp_dir->filename()/passwords.cfg] 
            } 
        ),
        pipe_command( 
            "cat $temp_dir->filename()/passwords.cfg",
            command( "dd of='/remote/config/passwords.cfg'", {hostname=>'remote_host'} ) );
    )
);
replace_map

A map used to construct a sed expression where the key is the match portion and the value is the replace portion. For example: {'key'=>'value'} would result in 's/key/value/g'.

temp_script_file

Specifies a file to write the sed script to rather than using the console. This is useful for avoiding generating commands that would get executed in the console that have protected information like passwords. If passwords are issued on the console, they might show up in the command history...

tail_command($filename, [\%tail_options], [$command_options])

Will read lines from the end of $filename. The supported tail options are:

follow

If truthy, new lines will be read as the file gets written to.

lines

The number of lines to obtain from the end fo the file.

write_command($filename, @lines, [\%write_options], [$command_options])

Will write @lines to $filename. The supported write options are:

mode

The file mode to set for $filename.

line_separator

The the separator to use between lines (default: \n).

AUTHOR

Lucas Theisen <lucastheisen@pastdev.com>

COPYRIGHT AND LICENSE

This software is copyright (c) 2016 by Lucas Theisen.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.

SEE ALSO

Please see those modules/websites for more information related to this module.