如何将shell脚本翻译为Perl?

时间:2009-07-20 08:43:27

标签: perl shell

我有一个shell脚本,非常大。现在我的老板说我必须用Perl重写它。 有没有办法编写Perl脚本并使用现有的shell代码,就像在我的Perl脚本中一样。与Inline::C类似的东西。

是否有像Inline :: Shell这样的东西?我看了一下内联模块,但它只支持语言。

6 个答案:

答案 0 :(得分:75)

答案 1 :(得分:5)

我不知道你的shell脚本中有什么,但不要忘记有像

这样的工具
  1. a2p - awk-to-perl
  2. s2p - sed-to-perl
  3. 也许更多。值得一看。

    你可能会发现,由于Perl的功能/功能,它并不是一项大工作,因为你可能已经通过各种bash功能和实用程序来跳过Perl本地出来的东西。

    与任何迁移项目一样,使用两种解决方案运行一些预制回归测试很有用,所以如果你没有这些,我会先生成这些。

答案 2 :(得分:5)

我很惊讶没有人提到核心Perl中包含的Shell module,它允许您使用函数调用语法执行外部命令。例如(改编自概要):

use Shell qw(cat ps cp);
$passwd = cat '</etc/passwd';
@pslines = ps '-ww';
cp "/etc/passwd", "/tmp/passwd";

如果您使用了parens,您甚至可以拨打$PATH中未提及use行的其他程序,例如:

gcc('-o', 'foo', 'foo.c');

请注意Shell收集子进程的STDOUT并将其作为字符串或数组返回。这简化了脚本编写,但它不是最有效的方法,如果您依赖命令的输出是无缓冲的,可能会造成麻烦。

模块文档提到了一些缺点,例如无法使用相同的语法调用shell内部命令(例如cd)。实际上,他们建议不要将该模块用于生产系统!但是,在您将代码移植到“正确的”Perl之前,它肯定是一个有用的拐杖。

答案 3 :(得分:4)

内联shell thingy称为system。如果你有用户定义的函数,你试图向Perl公开,那你就不走运了。但是,您可以使用与运行Perl程序相同的环境来运行短的shell。您还可以使用Perl逐步替换shell脚本的部分内容。开始编写一个复制shell脚本功能的模块,并将Perly位插入shell脚本,直到你最终拥有Perl。

没有shell-to-Perl翻译器。有一个关于csh-to-Perl翻译器的长篇笑话,你可以通过电子邮件发送你的脚本,但那真的只是Tom Christainsen为你翻译它,向你展示Perl在90年代早期的回归。 Randal Schwartz上传了一个sh-to-Perl翻译器,但你必须检查上传日期:这是愚人节。他的剧本只包括system中的所有内容。

无论你做什么,都不要丢失原始的shell脚本。 :)

答案 4 :(得分:1)

我同意学习Perl并尝试编写Perl而不是shell来获得更大的好处。我在Notepad ++的“替换”功能的帮助下完成了一次传输。

但是,当我尝试围绕shell脚本(可以执行它)创建一个Perl包装器时,我遇到了类似的问题。

我附带了以下适用于我的情况的代码。

这可能会有所帮助。

#!perl
use strict;
use Data::Dumper;
use Cwd;

#Variables read from shell
our %VAR;

open SH, "<$ARGV[0]" or die "Error while trying to read $ARGV[0] ($!)\n";
my @SH=<SH>;
close SH;

sh2perl(@SH);


#Subroutine to execute shell from Perl (read from array)
sub sh2perl {
    #Variables
    my %case; #To store data from conditional block of "case"
    my %if; #To store data from conditional block of "if"

    foreach my $line (@_) {
        #Remove blanks at the beginning and EOL character
        $line=~s/^\s*//;
        chomp $line;

        #Comments and blank lines
        if ($line=~/^(#.*|\s*)$/) {
            #Do nothing
        }

        #Conditional block - Case
        elsif ($line=~/case.*in/..$line=~/esac/) {
            if ($line=~/case\s*(.*?)\s*\in/) {
                $case{'var'}=transform($1);
            } elsif ($line=~/esac/) {
                delete $case{'curr_pattern'};
                #Run conditional block
                my $case;
                map { $case=$_ if $case{'var'}=~/$_/ } @{$case{'list_patterns'}};
                $case ? sh2perl(@{$case{'patterns'}->{$case}}) : sh2perl(@{$case{'patterns'}->{"*"}});
            } elsif ($line=~/^\s*(.*?)\s*\)/) {
                $case{'curr_pattern'}=$1;
                push(@{$case{'list_patterns'}}, $case{'curr_pattern'}) unless ($line=~m%\*\)%)
            } else {
                push(@{$case{'patterns'}->{ $case{'curr_pattern'} }}, $line);
            }
        }

        #Conditional block - if
        elsif ($line=~/^if/..$line=~/^fi/) {
            if ($line=~/if\s*\[\s*(.*\S)\s*\];/) {
                $if{'condition'}=transform($1);
                $if{'curr_cond'}="TRUE";
            } elsif ($line=~/fi/) {
                delete $if{'curr_cond'};
                #Run conditional block
                $if{'condition'} ? sh2perl(@{$if{'TRUE'}}) : sh2perl(@{$if{'FALSE'}});
            } elsif ($line=~/^else/) {
                $if{'curr_cond'}="FALSE";
            } else {
                push(@{$if{ $if{'curr_cond'} }}, $line);
            }
        }

        #echo
        elsif($line=~/^echo\s+"?(.*?[^"])"?\s*$/) {
            my $str=$1;
            #echo with redirection
            if ($str=~m%[>\|]%) { 
                eval { system(transform($line)) };
                if ($@) { warn "Error while evaluating $line: $@\n"; }
            #print new line
            } elsif ($line=~/^echo ""$/) {
                print "\n";
            #default
            } else {
                print transform($str),"\n";
            }
        }

        #cd
        elsif($line=~/^\s*cd\s+(.*)/) {
            chdir $1;
        }

        #export
        elsif($line=~/^export\s+((\w+).*)/) {
            my ($var,$exported)=($2,$1);
            if ($exported=~/^(\w+)\s*=\s*(.*)/) {
                while($exported=~/(\w+)\s*=\s*"?(.*?\S)"?\s*(;(?:\s*export\s+)?|$)/g) { $VAR{$1}=transform($2); }
            }
            # export($var,$VAR{$var});
            $ENV{$var}=$VAR{$var};
            print "Exported variable $var = $VAR{$var}\n";
        }


        #Variable assignment
        elsif ($line=~/^(\w+)\s*=\s*(.*)$/) {
            $1 eq "" or $VAR{$1}=""; #Empty variable
            while($line=~/(\w+)\s*=\s*"?(.*?\S)"?\s*(;|$)/g) {
                $VAR{$1}=transform($2);
            }
        }

        #Source
        elsif ($line=~/^source\s*(.*\.sh)/) {
            open SOURCE, "<$1" or die "Error while trying to open $1 ($!)\n";
            my @SOURCE=<SOURCE>;
            close SOURCE;
            sh2perl(@SOURCE);
        }


        #Default (assuming running command)
        else {
            eval { map { system(transform($_)) } split(";",$line); };
            if ($@) { warn "Error while doing system on \"$line\": $@\n"; }
        }

    }
}


sub transform {
    my $src=$_[0];

    #Variables $1 and similar
    $src=~s/\$(\d+)/$ARGV[$1-1]/ge;

    #Commands stored in variables "$(<cmd>)"
    eval {
        while ($src=~m%\$\((.*)\)%g) {
            my ($cmd,$new_cmd)=($1,$1);
            my $curr_dir=getcwd;
            $new_cmd=~s/pwd/echo $curr_dir/g;
            $src=~s%\$\($cmd\)%`$new_cmd`%e;
            chomp $src;
        }
    };
    if ($@) { warn "Wrong assessment for variable $_[0]:\n=> $@\n"; return "ERROR"; }

    #Other variables
    $src=~s/\$(\w+)/$VAR{$1}/g;

    #Backsticks
    $src=~s/`(.*)`/`$1`/e;

    #Conditions
    $src=~s/"(.*?)"\s*==\s*"(.*?)"/"$1" eq "$2" ? 1 : 0/e;
    $src=~s/"(.*?)"\s*!=\s*"(.*?)"/"$1" ne "$2" ? 1 : 0/e;
    $src=~s/(\S+)\s*==\s*(\S+)/$1 == $2 ? 1 : 0/e;
    $src=~s/(\S+)\s*!=\s*(\S+)/$1 != $2 ? 1 : 0/e;

    #Return Result
    return $src;
}

答案 5 :(得分:-15)

嗯...

您可以使用以下命令启动“Perl”脚本:

#!/bin/bash

然后,假设在该位置安装了bash,perl将自动调用bash解释器来运行它。

编辑:或者操作系统可能会拦截该呼叫并阻止它转到Perl。我发现很难找到关于它如何实际工作的文档。对文件的评论将受到欢迎。