How can I translate a shell script to Perl?

前端 未结 6 1925
长情又很酷
长情又很酷 2021-01-30 15:31

I have a shell script, pretty big one. Now my boss says I must rewrite it in Perl. Is there any way to write a Perl script and use the existing shell code as is in my Perl scrip

6条回答
  •  孤街浪徒
    2021-01-30 15:35

    I agree that learning Perl and trying to write Perl instead of shell is for the greater good. I did the transfer once with the help of the "Replace" function of Notepad++.

    However, I had a similar problem to the one initially asked while I was trying to create a Perl wrapper around a shell script (that could execute it).

    I came with the following code that works in my case.

    It might help.

    #!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=;
    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=;
                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 "$()"
        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;
    }
    

提交回复
热议问题