Lazer
Lazer

Reputation: 94820

How can I capture the complete commandline in Perl?

Suppose the call was

/usr/local/bin/perl verify.pl 1 3 de# > result.log

Inside verify.pl I want to capture the whole call above and append it to a log file for tracking purposes.

How can I capture the whole call as it is?

Upvotes: 10

Views: 14142

Answers (6)

HansS
HansS

Reputation: 1

Example which handles more special cases (and without adding own name) and with processing the line with GetOpt:

#!perl
use strict;
use warnings;
use Getopt::Long qw(GetOptionsFromString);
use feature qw ( say );

# Note: $0 is own name

my $sScriptCommandLine;
my @asArgs = ();

my $iRet;

my $sFile = '';
my $iN = -1;
my $iVerbose = 0;

# ============================================================================
my %OptionsHash = (
    "f=s"               => \$sFile,
    "n=i"               => \$iN,
    "v:+"               => \$iVerbose);



$sScriptCommandLine = join( ' ', @ARGV );  # useless for argument with spaces
say 'A: ' . $sScriptCommandLine;

$sScriptCommandLine = '"' . join( '" "', @ARGV ) . '"'; # all arguments in "", but not suitable for arguments with '"' (given as '\"')
say 'B: ' . $sScriptCommandLine;

$sScriptCommandLine = '';
foreach (@ARGV) {
  $sScriptCommandLine .= ' ' if ($sScriptCommandLine);
  $_ =~ s/\\/\\\\/g; # needed for GetOptionsFromString
  $_ =~ s/\"/\\\"/g;
  if (/\s/) {
    $sScriptCommandLine .= '"'.$_.'"';
  }
  else {
    $sScriptCommandLine .= $_;
  }
}
say 'C: ' . $sScriptCommandLine;


my ($iRet,$paArgs);
($iRet,$paArgs) = GetOptionsFromString($sScriptCommandLine,%OptionsHash);
# remaining parameters in $$paArgs[0] etc. 
if (!$iRet) {
  # error message already printed from GetOptionsFromString
  print "Invalid parameter(s) in: \"$sScriptCommandLine\"\n";
}

say 'D: ' . '<<' . join( '>>  <<', @{$paArgs} ) . '>>';
say 'f=s: "'.$sFile.'"'; 
say 'n=i: '.$iN; 
say 'v:+: '.$iVerbose; 

# eof

Upvotes: -1

Elko Mahinga
Elko Mahinga

Reputation: 11

Here virtually same Linux-only variants (of course, after shell intervention):

pure perl

BEGIN {
    my @cmd = ( );
    if (open(my $h, "<:raw", "/proc/$$/cmdline")) {
        # precisely, buffer size must be at least `getconf ARG_MAX`
        read($h, my $buf, 1048576); close($h);
        @cmd = split(/\0/s, $buf);
    };
    print join("\n\t", @cmd), "\n";
};

using File::Slurp:

BEGIN {
    use File::Slurp;
    my @cmd = split(/\0/s, File::Slurp::read_file("/proc/$$/cmdline", {binmode => ":raw"}));
    print join("\n\t", @cmd), "\n";
};

Upvotes: 1

Zhao Cai
Zhao Cai

Reputation: 21

$commandline = join " ", $0, @ARGV; does not handle the case that command line has quotes such as ./xxx.pl --love "dad and mom"

A Quick Solution:

my $script_command = $0;
foreach (@ARGV) {
$script_command .= /\s/ ?   " \'" . $_ . "\'"
                :           " "   . $_;
}

Try to save the following code as xxx.pl and run ./xxx.pl --love "dad and mom":

#!/usr/bin/env perl -w
use strict;
use feature qw ( say );
say "A: " . join( " ", $0, @ARGV );
my $script_command = $0;
foreach (@ARGV) {
    $script_command .= /\s/ ?   " \'" . $_ . "\'"
                    :           " "   . $_;
}
say "B: " . $script_command;

Upvotes: 2

w.k
w.k

Reputation: 8376

There is way (at least on unix-systems) to get whole command line:

my $cmdline = `ps -o args -C perl | grep verify.pl`;
print $cmdline, "\n";

e: Cleaner way using PID (courtesy of Nathan Fellman):

print qx/ps -o args $$/;

Upvotes: 10

Nathan Fellman
Nathan Fellman

Reputation: 127428

$0 has the script name and @ARGV has the arguments, so the whole commandline is:

$commandline = $0 . " ". (join " ", @ARGV);

or, more elegantly (thanks FMc):

$commandline = join " ", $0, @ARGV;

I don't however, know how to capture the redirection (> result.log)

Upvotes: 10

Related Questions