我有一个shell脚本,非常大。现在我的老板说我必须用Perl重写它。 有没有办法编写Perl脚本并使用现有的shell代码,就像在我的Perl脚本中一样。与Inline::C类似的东西。
是否有像Inline :: Shell这样的东西?我看了一下内联模块,但它只支持语言。
答案 0 :(得分:75)
答案 1 :(得分:5)
我不知道你的shell脚本中有什么,但不要忘记有像
这样的工具答案 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。我发现很难找到关于它如何实际工作的文档。对文件的评论将受到欢迎。