免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 10525 | 回复: 7
打印 上一主题 下一主题

#Perl @ARGV的返回值问题-高手请! [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-06-13 16:20 |只看该作者 |倒序浏览
感谢各位高手:)   麻烦大家帮忙看看,谢谢~~

#!/usr/bin/perl -w
#LastUpdated:2006-06-13


#这是一个日志分割程序,实现功能如下示例:
# rotate the named log file and archive $howmany old versions.  eg,
# rotate("foo",3);
# will move foo -> foo.0 -> foo.1 -> foo.2 -> foo.3
# and remove old foo.3, then create empty foo.

#程序执行的格式: ./logrotate.pl  -r 3 logfile  其中,3为保留日志的个数,在后面也做for循环的范围变量;

#1. @ARGV 这个系统变量,我理解的是@ARGV 存储了 程序后面加载的所有参数,也就是 (-r 3 logfile);
#我分别在Line.21 ,Line.56 行输出@ARGV,但@ARGV只有一个 logfile名,那么 (-r 3 )这些值都到那里去了呢?
#那么在Line.53 行,语句:"rotate ($file,$opt{'r'});" 怎么能确定logfile名呢?如果只能返回logfile,那么如下语句:my($file,$howmany) = @_;如何给$howmany符值为3的呢?

#2.函数scalar,是转换标量??不理解他的具体作用.
#3. $$ 系统变量是得到当前程序的PID?? sub rotate ($$) 在这里的用途是什么呢?

代码如下:  (代码被删减过,有两个sub没有体现,但不影响阅读.)

use strict;
use constant USAGE => "usage:logrotate [-z] [-p PID] [-s SIG] -r N file...\n";

use IO::File;
use Getopt::Std;

my %opt = ();
getopts('zp:s:r:',\%opt);

###print ("argv1: @ARGV\n";

scalar(@ARGV) or die USAGE;        # are there files specified?
die USAGE unless $opt{'r'};


sub rotate ($$) {
  my($file,$howmany) = @_;
  print ("$howmany";
  my($cur);

  return if ($howmany < 0);

  unlink ("$file.$howmany","$file.$howmany.gz"; # remove topmost one.

  for ($cur = $howmany; $cur > 0; $cur--) {
    my $prev = $cur - 1;
    rename("$file.$prev","$file.$cur" if (-f "$file.$prev";
    rename("$file.$prev.gz","$file.$cur.gz" if (-f "$file.$prev.gz";
  }

  rename("$file","$file.0";    # move original one

  # create the new one!
  my $fh = new IO::File $file, O_WRONLY|O_CREAT, 0644;
  $fh->close();
}

# MAIN
# first rotate the files
foreach my $file (@ARGV) {
        ###print ("argv2: @ARGV\n"
  rotate ($file,$opt{'r'});
}

exit(0);

[[i] 本帖最后由 joyaid 于 2006-6-14 09:55 编辑 [/i]]

论坛徽章:
0
2 [报告]
发表于 2006-06-13 18:29 |只看该作者
不会巴??自己顶!

论坛徽章:
0
3 [报告]
发表于 2006-06-14 00:53 |只看该作者
连表情符号都不过滤  谁帮你看!

论坛徽章:
0
4 [报告]
发表于 2006-06-14 09:55 |只看该作者
编辑过了.去掉了表情符号!

论坛徽章:
1
技术图书徽章
日期:2013-12-05 23:25:45
5 [报告]
发表于 2006-06-14 10:37 |只看该作者
1。GetOptions用来获取命令”...
   摘自 精彩奇讯网络软件开发组   mudga  946646576
http://fund.perlchina.org/com/ccb/index.cgi
1。GetOptions用来获取命令行参数值或者调用相应程序,例如:(取自perldoc)
use Getopt::Long;
   my $data  = "file.dat";
   my $length = 24;
   my $verbose;
   $result = GetOptions ("length=i" => \$length,  # numeric
              "file=s"  => \$data,   # string
              "verbose" => \$verbose); # flag

调用的例子:
GetOptions("version" => \&print_version,

论坛徽章:
0
6 [报告]
发表于 2006-06-14 11:14 |只看该作者

非常感谢版主 HonestQiao的点拨!

问题1出在这里与@ARGV无关:getopts('zp:s:r:',\%opt);
关于getopts 函数,在chinaunix bbs perl 2004-9-23 有写到.具体内容如下:

_Begin_

使用Getopt::Std解析命令行中的选项

Perl脚本经常用于编写并执行被命令行选项(command-line options)控制的相关行为,这方面的例子包括请求帮助和可以改变程序输出的冗长程度。



Perl具有很多由基本get选项函数变异而来的函数,但这一文章主要集中于Getopt::Std模块中的getopts()函数。

Getopts是一个简单而又灵活的程序,用于处理单一字符命令行选项。以合法的命令行选项调用getopts(),结果可以得到一个可选择的hash引用。

选项字符串包含一个列表的字母,这些字母表示合法的命令行选项。紧跟着一个字母之后的冒号(:)可以表示可用于选项的变量。以下是一个简单的范例:

useGetopt::Std;

getopts('hmf:');

你可以采用两种方式来解析和设定你的选项参数。如果命令行为a-h,变量$opt_h将为1,类似的,如果命令行为a-m,变量$opt_m将为1。如果命令行为a-f,它之后将紧跟着一个字符串变量,如果出现一个变量,$opt_f将设定为字符型。

以下是更加完整的范例:

use Getopt::Std;

getopts('hmf:');

die "Usage: $0 [-h] [-m] [-f string]\n" if ($opt_h);

print "Option M was present\n" if ($opt_m);

print "Option F was passed '$opt_f'\n" if ($opt_f);

print "No options\n" if (!$opt_f && !$opt_m);

使用getopts可以节省你的时间,并简化你的代码,特别是当你需要处理程序中的命令行选项的时候。

_END_

URL: [url]http://bbs.chinaunix.net/archiver/?tid-412964.html[/url]

论坛徽章:
1
技术图书徽章
日期:2013-12-05 23:25:45
7 [报告]
发表于 2006-06-14 15:38 |只看该作者
4.0 函数原型

Perl 可以让你定义你自己的函数,这些函数可以象 Perl 的内建函数一样调用.例如 push(@array, $item),它必须接收一个 @array 的引用,而不仅仅是 @array 中的值,这样这个数组才能够被函数改变.函数原型能够让你声明的子过程能够象很多内建函数一样获得参数,就是获得一定数目和类型的参数.我们虽然称之为函数原型,但是它们的运转更像调用环境中的自动模板,而不仅仅是 C 或 java 程序员认为的函数原型.使用这些模板,Perl 能够自动添加隐含的反斜扛或者调用 scalar,或能够使事情能变成符合模板的其他一些操作.比如,如果你定义:

   sub mypush (\@@);

那么 mypush 就会象 push 一样接受参数.为了使其运转,函数的定义和调用在编译的时候必须是可见的.函数原型只影响那些不带 & 方式调用的函数.换句话说,如果你象内建函数一样调用它,它就像内建函数一样工作.如果你使用老式的方法调用子过程,那么它就象老式子过程那样工作.调用中的 & 消除所有的原型检查和相关的环境影响.

因为函数原型仅仅在编译的时候起作用,自然它对象 \&foo 这样的子过程引用和象 &{$subref} 和 $subref->() 这样的间接子过程调用的情况不起作用.同样函数原型在方法调用中也不起作用.这是因为被调用的实际函数不是在编译的时候决定的,而是依赖于它的继承,而继承在 Perl 中是动态判断的.

因为本节的重点主要是让你学会定义象内建函数一样工作的子过程,下面使一些函数原型,你可以用来模仿对应的内建函数:

声明为         调用
sub mylink ($$)         mylink $old, $new
sub myreverse (@)         myreverse $a, $b, $c
sub myjoin ($@)         myjoin ":", $a, $b, $c
sub mypop (\@)         mypop @array
sub mysplice(\@$$@)         mysplice @array, @array, 0, @pushme
sub mykeys (\%)         mykeys %($hashref)
sub mypipe (**)         mypipe READHANDLE, WRITEHANDLE
sub myindex ($$;$)         myindex &getstring, "substr"
          myindex &getstring, "substr", $start
sub mysyswrite (*$;$$)         mysyswrite OUTF, $buf
          mysyswrite OUTF, $buf, length($buf)-$off, $off
sub myopen (*;$@)         myopen HANDLE
          myopen HANDLE, $name
          myopen HANDLE, "-|", @cmd
sub mygrep (&@)         mygrep { /foo/ } $a, $b, $c
sub myrand ($)         myrand 42
sub mytime ()         mytime

任何带有反斜扛的原型字符(在上表左列中的圆括弧里)代表一个实际的参数(右列中有示例) 必须以以这个字符开头.例如 keys 函数的第一个参数必须以 % 开始,同样 mykeys 的第一个参数也必须以 % 开头.

分号将命令性参数和可选参数分开.(在 @ 或 % 前是多余的,因为列表本身就可以是空的) .非反斜扛函数原型字符有特殊的含义.任何不带反斜扛的 @ 或 % 会将实际参数所有剩下的参数都吃光并强制进入列表环境.(等同于语法描述中的 LIST).$ 代表的参数强迫进入标量环境.& 要求一个命名或匿名子过程的引用.

函数原型中的 * 允许子过程在该位置接受任何参数,就像内建的文件句柄那样:可以是一个名字,一个常量,标量表达式,类型团或者类型团的引用.值将可以当成一个简单的标量或者类型团(用小写字母的)的引用由子过程使用.如果你总是希望这样的参数转换成一个类型团的引用,可以使用 Symbol::qualify_to_ref,象下面这样:

use Symblo 'qualify_to_ref';

sub foo (*) {
        my $fh = qualify_to_ref(shift, caller);
        ...
}

注意上面表中的最后三个例子会被分析器特殊对待,mygrep 被分析成一个真的列表操作符,myrand 被分析成一个真的单目操作符就象 rand 一样,同样 mytime 被分析成没有参数,就象 time 一样.

也就是说,如果你使用下面的表达式:

   mytime +2;

你将会得到 mytime()+2,而不是 mytime(2),这就是在没有函数原型时和使用了单目函数原型时分析的得到的不同结果.

mygrep 例子同样显示了当 & 是第一个参数的时候是如果处理的.通常一个 & 函数原型要求一个象 \&foo 或 sub{} 这样参数.当它是第一个参数时,你可以在你的匿名子过程中省略掉 sub,只在"非直接对象"的位置上传送一个简单的程序块(不带冒号).所以 & 函数原型的一个重要功能就是你可以用它生成一个新语法,只要 & 是在初始位置:

sub try (&$) {
        my ($try, $catch) = @_;
        eval { &$try };
        if ($@) {
                local $_ = $@;
                &$catch;
        }
}
sub catch (&) { $_[0] }

try {
        die "phooey";
}         # 不是函数调用的结尾!
catch {
        /phooey/ and print "unphooey\n";
};

它打印出 "unphooey".这里发生的事情是这样的,Perl 带两个参数调用了 try,匿名函数 {die "phooey";} 和 catch 函数的返回值,在本例中这个返回值什么都不是,只不过是它自己的参数,而整个块则是另外一个匿名函数.在 try 里,第一个函数参数是在 eval 里调用的,这样就可以捕获任何错误.如果真的出了错误,那么调用第二个函数,并且设置 $_ 变量以抛出例外.(注:没错,这里仍然有涉及 @_ 的可视性的问题没有解决.目前我们忽略那些问题.但是如果我们将来把 @_ 做成词法范围的东西,就象现在试验的线程化 Perl 版本里已经做的那样,那么那些匿名子过程就可以象闭合的行为一样.)如果你觉得这些东西听起来象胡说八道,那么你最好看看第二十九章里的 die 和 eval,然后回到第八章里看看匿名函数和闭合.另外,如果你觉得麻烦,你还可以看看 CPAN 上的 Error 模块,这个模块就是实现了一个用 try,catch,except,otherwise,和 finally 子句的灵活的结构化例外操作机制.

下面是一个 grep 操作符的重新实现(当然内建的实现更为有效):

sub mygrep (&@) {
        my $coderef = shift;
        my @result;
        foreach $_ (@_) {
                push(@result, $_) if &$coderef;
        }
        return @result;
}

一些读者希望能够看到完整的字母数字函数原型.我们有意把字母数字放在了原型之外,为的是将来我们能够很快地增加命名的,正式的参数.(可能)现在函数原型的主要目的就是让模块作者能够对模块用户作一些编译时的强制参数检查.









因而:
sub mylink ($$)          mylink $old, $new
分号将命令性参数和可选参数分开.(在 @ 或 % 前是多余的,因为列表本身就可以是空的) .非反斜扛函数原型字符有特殊的含义.任何不带反斜扛的 @ 或 % 会将实际参数所有剩下的参数都吃光并强制进入列表环境.(等同于语法描述中的 LIST).$ 代表的参数强迫进入标量环境.& 要求一个命名或匿名子过程的引用.

论坛徽章:
0
8 [报告]
发表于 2006-06-14 16:58 |只看该作者
理解了!多谢 HonestQiao版主!
结贴!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP