如何在Perl中捕获完整的命令行?
假设电话是如何在Perl中捕获完整的命令行?,perl,command-line,Perl,Command Line,假设电话是 /usr/local/bin/perl verify.pl 1 3 de# > result.log 在verify.pl内部,我想捕获上面的整个调用,并将其附加到日志文件中以便于跟踪 如何按原样捕获整个调用?$0有脚本名,@ARGV有参数,因此整个命令行是: $commandline=$0。" ". (加入“”@ARGV) 或者,更优雅地说(谢谢): $commandline=join”“,$0,@ARGV 但是,我不知道如何捕获重定向(>result.log)请参阅有一种
/usr/local/bin/perl verify.pl 1 3 de# > result.log
在verify.pl
内部,我想捕获上面的整个调用,并将其附加到日志文件中以便于跟踪
如何按原样捕获整个调用?
$0
有脚本名,@ARGV
有参数,因此整个命令行是:
$commandline=$0。" ". (加入“”@ARGV)代码>
或者,更优雅地说(谢谢):
$commandline=join”“,$0,@ARGV代码>
但是,我不知道如何捕获重定向(>result.log
)请参阅有一种方法(至少在unix系统上)可以获取整个命令行:
my $cmdline = `ps -o args -C perl | grep verify.pl`;
print $cmdline, "\n";
e:使用PID的清洁方式(由Nathan Fellman提供):
$commandline=join”“,$0,@ARGV
不处理命令行中有引号的情况,例如/xxx.pl--love“dad and mom”
快速解决方案:
my $script_command = $0;
foreach (@ARGV) {
$script_command .= /\s/ ? " \'" . $_ . "\'"
: " " . $_;
}
尝试将以下代码保存为xxx.pl
并运行/xxx.pl--love“爸爸妈妈”
:
这里实际上是相同的Linux版本(当然,在shell干预之后):
纯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";
};
处理更多特殊情况(且不添加自己的名称)和使用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
#!perl
严格使用;
使用警告;
使用Getopt::Long qw(GetOptionsFromString);
使用特征qw(例如);
#注意:$0是自己的名字
我的$sScriptCommandLine;
我的@asArgs=();
我的$iRet;
我的$sFile='';
我的$iN=-1;
我的$iVerbose=0;
# ============================================================================
我的%OptionsHash=(
“f=s”=>\$s文件,
“n=i”=>\$iN,
“v:+”=>\$iVerbose);
$sScriptCommandLine=join(“”,@ARGV)#不适用于与空格进行辩论
说“A:”$sScriptCommandLine;
$sScriptCommandLine=''''''''。连接(''''''''',@ARGV)。''''.#“”中的所有参数,但不适用于带“”的参数(以“\”形式给出)
说“B:”$sScriptCommandLine;
$sScriptCommandLine='';
foreach(@ARGV){
$sScriptCommandLine.=''如果($sScriptCommandLine);
GetOptionsFromString需要$\\=~s/\\\/\\\\\\\\/g;#
$\\=~s/\“/\\\”/g;
如果(/\s/){
$sScriptCommandLine.=''.$'.'''.'''.'''.'''.';
}
否则{
$sScriptCommandLine.=$\ux;
}
}
说“C:”$sScriptCommandLine;
我的($iRet,$paArgs);
($iRet,$paArgs)=GetOptionsFromString($sScriptCommandLine,%OptionsHash);
#$$paArgs[0]等中的剩余参数。
如果(!$iRet){
#已从GetOptionsFromString打印错误消息
打印“$sScriptCommandLine\”中的“无效参数”\n;
}
说“D:”;
说“f=s:”.$sFile.”;
说‘n=i:’。$iN;
说“v:+:”。$iVerbose;
#eof
我认为您不能,因为shell只是dup
将STDOUT的文件描述符指向该日志文件。据我所知,Perl无法知道是否发生了这种情况。(您可以通过使用-t
来检测是否发生了输入重定向。)FWIW,join
接受多个参数:join(“,$0,@ARGV)
。可以在运行时使用$^X
或$Config{perlpath}
访问perl可执行文件的路径(如果您已加载Config
模块)。$Config{perlpath}
在某些情况下更可取,因为它是一个只读变量。无法捕获重定向。它由shell管理,即shell(bash、sh、cmd——无论什么)将打开文件然后在不使用>
的情况下运行该命令。但是,可以猜测某个文件句柄是终端、文件还是管道。请注意,@ARGV
会被GetOptions()
使用,因此您需要在之前执行此操作。这很好,除非您运行了多个perl实例。您可以使用getpid>过滤掉它()
@Nathan Fellman:是的,从流程中获得正确的答案可能会有一些问题,但我认为OP可以自己决定如何正确过滤特定流程。通过PID或某种grep模式,或者……我正在考虑使用类似于打印qx/ps-o args$$$/;
的方法,为什么不编辑您的答案并获得更多的投票呢?:-)这似乎无法维护命令行上使用的shell引用,这可能是一个问题,取决于原始命令行的用途。这太神奇了。这正是我要寻找的。你能解释一下这是如何工作的吗?不确定你在这里做什么
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";
};
BEGIN {
use File::Slurp;
my @cmd = split(/\0/s, File::Slurp::read_file("/proc/$$/cmdline", {binmode => ":raw"}));
print join("\n\t", @cmd), "\n";
};
#!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