The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
<html><head><title>Footprintless::Command</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" >

<style type="text/css">
 <!--/*--><![CDATA[/*><!--*/
BODY {
  background: white;
  color: black;
  font-family: arial,sans-serif;
  margin: 0;
  padding: 1ex;
}

A:link, A:visited {
  background: transparent;
  color: #006699;
}

A[href="#POD_ERRORS"] {
  background: transparent;
  color: #FF0000;
}

DIV {
  border-width: 0;
}

DT {
  margin-top: 1em;
  margin-left: 1em;
}

.pod { margin-right: 20ex; }

.pod PRE     {
  background: #eeeeee;
  border: 1px solid #888888;
  color: black;
  padding: 1em;
  white-space: pre;
}

.pod H1      {
  background: transparent;
  color: #006699;
  font-size: large;
}

.pod H1 A { text-decoration: none; }
.pod H2 A { text-decoration: none; }
.pod H3 A { text-decoration: none; }
.pod H4 A { text-decoration: none; }

.pod H2      {
  background: transparent;
  color: #006699;
  font-size: medium;
}

.pod H3      {
  background: transparent;
  color: #006699;
  font-size: medium;
  font-style: italic;
}

.pod H4      {
  background: transparent;
  color: #006699;
  font-size: medium;
  font-weight: normal;
}

.pod IMG     {
  vertical-align: top;
}

.pod .toc A  {
  text-decoration: none;
}

.pod .toc LI {
  line-height: 1.2em;
  list-style-type: none;
}

  /*]]>*/-->
</style>


</head>
<body class='pod'>
<!--
  generated by Pod::Simple::HTML v3.32,
  using Pod::Simple::PullParser v3.32,
  under Perl v5.025000 at Tue Feb 13 13:45:24 2018 GMT.

 If you want to change this HTML document, you probably shouldn't do that
   by changing it directly.  Instead, see about changing the calling options
   to Pod::Simple::HTML, and/or subclassing Pod::Simple::HTML,
   then reconverting this document from the Pod source.
   When in doubt, email the author of Pod::Simple::HTML for advice.
   See 'perldoc Pod::Simple::HTML' for more info.

-->

<!-- start doc -->
<a name='___top' class='dummyTopAnchor' ></a>

<div class='indexgroup'>
<ul   class='indexList indexList1'>
  <li class='indexItem indexItem1'><a href='#NAME'>NAME</a>
  <li class='indexItem indexItem1'><a href='#VERSION'>VERSION</a>
  <li class='indexItem indexItem1'><a href='#SYNOPSIS'>SYNOPSIS</a>
  <li class='indexItem indexItem1'><a href='#DESCRIPTION'>DESCRIPTION</a>
  <li class='indexItem indexItem1'><a href='#OPTIONS'>OPTIONS</a>
  <li class='indexItem indexItem1'><a href='#FUNCTIONS'>FUNCTIONS</a>
  <ul   class='indexList indexList2'>
    <li class='indexItem indexItem2'><a href='#batch_command(%24command1%2C_%24command2%2C_...%2C_%24commandN%2C_%5B%5C%25batch_options%5D%2C_%5B%24command_options%5D)'>batch_command($command1, $command2, ..., $commandN, [\%batch_options], [$command_options])</a>
    <li class='indexItem indexItem2'><a href='#command(%24command%2C_%5B%24command_options%5D)'>command($command, [$command_options])</a>
    <li class='indexItem indexItem2'><a href='#command_options(%25options)'>command_options(%options)</a>
    <li class='indexItem indexItem2'><a href='#cp_command(%24source_path%2C_%5B%24source_command_options%5D%2C_%24destination_path%2C_%5B%24destination_command_options%5D%2C_%25cp_options)'>cp_command($source_path, [$source_command_options], $destination_path, [$destination_command_options], %cp_options)</a>
    <li class='indexItem indexItem2'><a href='#mkdir_command(%24path1%2C_%24path2%2C_...%2C_%24pathN%2C_%5B%24command_options%5D)'>mkdir_command($path1, $path2, ..., $pathN, [$command_options])</a>
    <li class='indexItem indexItem2'><a href='#pipe_command(%24command1%2C_%24command2%2C_...%2C_%24commandN%2C_%5B%24command_options%5D)'>pipe_command($command1, $command2, ..., $commandN, [$command_options])</a>
    <li class='indexItem indexItem2'><a href='#rm_command(%24path1%2C_%24path2%2C_...%2C_%24pathN%2C_%5B%24command_options%5D)'>rm_command($path1, $path2, ..., $pathN, [$command_options])</a>
    <li class='indexItem indexItem2'><a href='#sed_command(%24expression1%2C_%24expression2%2C_...%2C_%24expressionN%2C_%5B%24command_options%5D)'>sed_command($expression1, $expression2, ..., $expressionN, [$command_options])</a>
    <li class='indexItem indexItem2'><a href='#tail_command(%24filename%2C_%5B%5C%25tail_options%5D%2C_%5B%24command_options%5D)'>tail_command($filename, [\%tail_options], [$command_options])</a>
    <li class='indexItem indexItem2'><a href='#write_command(%24filename%2C_%40lines%2C_%5B%5C%25write_options%5D%2C_%5B%24command_options%5D)'>write_command($filename, @lines, [\%write_options], [$command_options])</a>
  </ul>
  <li class='indexItem indexItem1'><a href='#AUTHOR'>AUTHOR</a>
  <li class='indexItem indexItem1'><a href='#COPYRIGHT_AND_LICENSE'>COPYRIGHT AND LICENSE</a>
  <li class='indexItem indexItem1'><a href='#SEE_ALSO'>SEE ALSO</a>
</ul>
</div>

<h1><a class='u' href='#___top' title='click to go to top of document'
name="NAME"
>NAME</a></h1>

<p>Footprintless::Command - A factory for building common commands</p>

<h1><a class='u' href='#___top' title='click to go to top of document'
name="VERSION"
>VERSION</a></h1>

<p>version 1.27</p>

<h1><a class='u' href='#___top' title='click to go to top of document'
name="SYNOPSIS"
>SYNOPSIS</a></h1>

<pre>  use Footprintless::Command qw(command batch_command mkdir_command pipe_command rm_command sed_command);
  my $command = command( &#39;echo&#39; ); # echo

  # ssh foo &#34;echo&#34;
  $command = command( &#39;echo&#39;, command_options( hostname=&#62;&#39;foo&#39; ) ); 

  # ssh bar@foo &#34;echo&#34;
  $command = command( &#39;echo&#39;, command_options( username=&#62;&#39;bar&#39;,hostname=&#62;&#39;foo&#39; ) ); 
  
  # plink -l bar foo &#34;echo&#34;
  $command = command( &#39;echo&#39;, command_options( username=&#62;&#39;bar&#39;,hostname=&#62;&#39;foo&#39;,ssh=&#62;&#39;plink&#39; ) ); 
  
  # cd foo;cd bar
  $command = batch_command( &#39;cd foo&#39;, &#39;cd bar&#39; ); 
  
  # ssh baz &#34;cd foo;cd bar&#34;
  $command = batch_command( &#39;cd foo&#39;, &#39;cd bar&#39;, command_options( hostname=&#62;&#39;baz&#39; ) ); 
  
  # ssh baz &#34;bash -c \&#34;sudo cd foo;sudo cd bar\&#34;&#34;
  $command = batch_command( &#39;cd foo&#39;, &#39;cd bar&#39;, {subshell =&#62; &#39;bash -c&#39; }, command_options( hostname=&#62;&#39;baz&#39;,sudo_username=&#62;&#39;&#39; ) ); 
  
  # ssh baz &#34;mkdir -p \&#34;foo\&#34; \&#34;bar\&#34;&#34;
  $command = mkdir_command( &#39;foo&#39;, &#39;bar&#39;, command_options( hostname=&#62;&#39;baz&#39; ) ); 

  # cat abc|ssh baz &#34;dd of=def&#34;
  $command = pipe_command( 
          &#39;cat abc&#39;, 
          command( &#39;dd of=def&#39;, command_options( hostname=&#62;&#39;baz&#39; ) ) 
      ); 

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

<h1><a class='u' href='#___top' title='click to go to top of document'
name="DESCRIPTION"
>DESCRIPTION</a></h1>

<p>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 <i>shelling</i> 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 <code>command_options</code> hash defining who/where/how to run the command.</p>

<h1><a class='u' href='#___top' title='click to go to top of document'
name="OPTIONS"
>OPTIONS</a></h1>

<h1><a class='u' href='#___top' title='click to go to top of document'
name="FUNCTIONS"
>FUNCTIONS</a></h1>

<h2><a class='u' href='#___top' title='click to go to top of document'
name="batch_command($command1,_$command2,_...,_$commandN,_[\%batch_options],_[$command_options])"
>batch_command($command1, $command2, ..., $commandN, [\%batch_options], [$command_options])</a></h2>

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

<dl>
<dt><a name="subshell"
>subshell</a></dt>

<dd>
<p>The subshell to run the commands under, must end with <code>-c</code>. (ex: <code>&#39;bash -c&#39;</code>)</p>
</dd>
</dl>

<h2><a class='u' href='#___top' title='click to go to top of document'
name="command($command,_[$command_options])"
>command($command, [$command_options])</a></h2>

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

<h2><a class='u' href='#___top' title='click to go to top of document'
name="command_options(%options)"
>command_options(%options)</a></h2>

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

<dl>
<dt><a name="ssh"
>ssh</a></dt>

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

<dt><a name="sudo_command"
>sudo_command</a></dt>

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

<dt><a name="sudo_username"
>sudo_username</a></dt>

<dd>
<p>Prefixes your command thusly: <code>sudo -u $sudo_username $command</code>. If combined with a remote hostname, the <code>sudo</code> will be executed on the remote system. For example: <code>ssh $hostname &#34;sudo -u $sudo_user \&#34;$command\&#34;&#34;</code>.</p>

<dt><a name="username"
>username</a></dt>

<dd>
<p>The username to <code>ssh</code> with. If using <code>ssh</code>, this will result in, <code>ssh $username@$hostname</code> but if using <code>plink</code> it will result in <code>plink -l $username $hostname</code>.</p>

<dt><a name="hostname"
>hostname</a></dt>

<dd>
<p>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 <code>ssh</code></p>
</dd>
</dl>

<h2><a class='u' href='#___top' title='click to go to top of document'
name="cp_command($source_path,_[$source_command_options],_$destination_path,_[$destination_command_options],_%cp_options)"
>cp_command($source_path, [$source_command_options], $destination_path, [$destination_command_options], %cp_options)</a></h2>

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

<dl>
<dt><a name="archive"
>archive</a></dt>

<dd>
<p>If specified and set to &#39;zip&#39;, then zip will be used to archive the source before sending it to the destination. Otherwise, tar will be used. Note, that if <code>file =&#62; 1</code> then this is ignored.</p>

<dt><a name="compress"
>compress</a></dt>

<dd>
<p>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 <code>archive =&#62; &#39;zip&#39;</code> then this is ignored as zip implies compression.</p>

<dt><a name="file"
>file</a></dt>

<dd>
<p>If supplied and true, then this is a file copy, otherwise it is a directory copy.</p>

<dt><a name="status"
>status</a></dt>

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

<h2><a class='u' href='#___top' title='click to go to top of document'
name="mkdir_command($path1,_$path2,_...,_$pathN,_[$command_options])"
>mkdir_command($path1, $path2, ..., $pathN, [$command_options])</a></h2>

<p>Results in <code>mkdir -p $path1 $path2 ... $pathN</code> with the <code>command_options</code> applied.</p>

<h2><a class='u' href='#___top' title='click to go to top of document'
name="pipe_command($command1,_$command2,_...,_$commandN,_[$command_options])"
>pipe_command($command1, $command2, ..., $commandN, [$command_options])</a></h2>

<p>Identical to <a href="#batch_command(_%24command1%2C_%24command2%2C_...%2C_%24commandN%2C_%5B%24command_options%5D_)" class="podlinkpod"
>batch_command</a> except uses <code>\|</code> to separate the commands instead of <code>;</code>.</p>

<h2><a class='u' href='#___top' title='click to go to top of document'
name="rm_command($path1,_$path2,_...,_$pathN,_[$command_options])"
>rm_command($path1, $path2, ..., $pathN, [$command_options])</a></h2>

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

<h2><a class='u' href='#___top' title='click to go to top of document'
name="sed_command($expression1,_$expression2,_...,_$expressionN,_[$command_options])"
>sed_command($expression1, $expression2, ..., $expressionN, [$command_options])</a></h2>

<p>Constructs a sed command</p>

<dl>
<dt><a name="files"
>files</a></dt>

<dd>
<p>An arrayref of files to apply the sed expressions to. For use when not piping from another command.</p>

<dt><a name="in_place"
>in_place</a></dt>

<dd>
<p>If specified, the <code>-i</code> option will be supplied to <code>sed</code> 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:</p>

<p><code>/my/config/passwords.cfg</code></p>

<pre>  app1.username=foo
  app1.password=##APP1_PASSWORD##
  app2.username=bar
  app2.password=##APP2_PASSWORD##</pre>

<p><code>deploy_passwords.pl</code></p>

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

<dt><a name="replace_map"
>replace_map</a></dt>

<dd>
<p>A map used to construct a sed expression where the key is the match portion and the value is the replace portion. For example: <code>{&#39;key&#39;=&#62;&#39;value&#39;}</code> would result in <code>&#39;s/key/value/g&#39;</code>.</p>

<dt><a name="temp_script_file"
>temp_script_file</a></dt>

<dd>
<p>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...</p>
</dd>
</dl>

<h2><a class='u' href='#___top' title='click to go to top of document'
name="tail_command($filename,_[\%tail_options],_[$command_options])"
>tail_command($filename, [\%tail_options], [$command_options])</a></h2>

<p>Will read lines from the end of <code>$filename</code>. The supported tail options are:</p>

<dl>
<dt><a name="follow"
>follow</a></dt>

<dd>
<p>If <i>truthy</i>, new lines will be read as the file gets written to.</p>

<dt><a name="lines"
>lines</a></dt>

<dd>
<p>The number of lines to obtain from the end fo the file.</p>
</dd>
</dl>

<h2><a class='u' href='#___top' title='click to go to top of document'
name="write_command($filename,_@lines,_[\%write_options],_[$command_options])"
>write_command($filename, @lines, [\%write_options], [$command_options])</a></h2>

<p>Will write <code>@lines</code> to <code>$filename</code>. The supported write options are:</p>

<dl>
<dt><a name="mode"
>mode</a></dt>

<dd>
<p>The file mode to set for <code>$filename</code>.</p>

<dt><a name="line_separator"
>line_separator</a></dt>

<dd>
<p>The the separator to use between lines (default: <code>\n</code>).</p>
</dd>
</dl>

<h1><a class='u' href='#___top' title='click to go to top of document'
name="AUTHOR"
>AUTHOR</a></h1>

<p>Lucas Theisen &#60;lucastheisen@pastdev.com&#62;</p>

<h1><a class='u' href='#___top' title='click to go to top of document'
name="COPYRIGHT_AND_LICENSE"
>COPYRIGHT AND LICENSE</a></h1>

<p>This software is copyright (c) 2016 by Lucas Theisen.</p>

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

<h1><a class='u' href='#___top' title='click to go to top of document'
name="SEE_ALSO"
>SEE ALSO</a></h1>

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

<ul>
<li><a href="http://search.cpan.org/perldoc?Footprintless" class="podlinkpod"
>Footprintless</a></li>

<li><a href="http://search.cpan.org/perldoc?Footprintless%3A%3ACommandRunner" class="podlinkpod"
>Footprintless::CommandRunner</a></li>
</ul>

<!-- end doc -->

</body></html>