Apr 29 2007

前几日搞perl的笔记

Category: 技术ssmax @ 14:36:54

前几天搞一个空间的时候,php被禁止了system命令,只有用perl cgi来做了,研究了一下perl调用命令行,弄了一个web版模拟shell。

先贴资料:

How can I capture STDERR from an external command?

There are three basic ways of running external commands:

    system $cmd;
     $output = `$cmd`;
     open (PIPE, "cmd |");

In the first case, both STDOUT and STDERR will go the same place as the script’s versions of these, unless redirected. You can always put them where you want them and then read them back when the system returns. In the second and third cases, you are reading the STDOUT only of your command. If you would like to have merged STDOUT and STDERR, you can use shell file-descriptor redirection to dup STDERR to STDOUT:

    $output = `$cmd 2>&1`;
     open (PIPE, "cmd 2>&1 |");

Another possibility is to run STDERR into a file and read the file later, as in

    $output = `$cmd 2>&some_file`;
     open (PIPE, "cmd 2>&some_file |");

Note that you cannot simply open STDERR to be a dup of STDOUT in your perl program and avoid calling the shell to do the redirection. This doesn’t work:

    open(STDERR, ">&STDOUT");
     $alloutput = `cmd args`;
  # stderr still escapes

Here’s a way to read from both of them and know which descriptor you got each line from. The trick is to pipe only STDOUT through sed, which then marks each of its lines, and then sends that back into a merged STDOUT/STDERR stream, from which your Perl program then reads a line at a time:

    open (CMD, "(cmd args | sed 's/^/STDOUT:/') 2>&1 |");
    while () {
       if (s/^STDOUT://)  {
           print "line from stdout: ", $_;
       } else {
           print "line from stderr: ", $_;
       }
     }

Be apprised that you must use Bourne shell redirection syntax in backticks, not csh! For details on how lucky you are that perl’s system() and backtick and pipe opens all use Bourne shell, fetch the file from convex.com called /pub/csh.whynot — and you’ll be glad that perl’s shell interface is the Bourne shell.

There’s an &open3 routine out there which was merged with &open2 in perl5 production.

再贴偶的模拟shell,随便写了个。。

cmd.pl

#!/usr/bin/perl
use CGI;
my $command = CGI::param(‘command’);
my $pwd = CGI::param(‘pwd’) || ‘.’;

print (“Content-Type: text/plain;\n\n”);
print “change dir: “.`cd $pwd 2>&1`.”\n”;
print “now dir: “.`pwd`.”\n”;
print “command: “.$command.”\n\n”;
print `$command 2>&1`;

cmd.html

<html>
<body>
 <form name=”cmdform” action=”cgi-bin/cmd.pl” target=”cmdframe”>
 <div>
  work dir:
  <input type=”text” value=”.” name=”pwd” />
 </div>
 <div>
  input your command here:
  <textarea name=”command” cols=”100″ rows=”5″></textarea>
 </div>
 <Input type=”submit” value=”run”/>
 </form>
 
 <iframe name=”cmdframe” height=”100%” width=”100%”></iframe>
</body>
</html>

如果遇到 500 错误,最有可能是没有设置cmd.pl为可执行(755一般是),这个在后台log应该能看到,还有可能是遇到apache的Premature end of script headers错误,一般就是没有

print (“Content-Type: text/plain;\n\n”);

这句造成的,还有可能是dos换行符号造成,把cmd.pl里面所有\r\n换成unix的\n格式就好了。。。

Leave a Reply