2017-09-25 54 views
1

我正在使用cygwin。 这个脚本的作用是加载我已经加载到桌面上的目录中的iphone图片。 它在图像查看器中打开它,让我看看图片。重命名外部作用域中的子使用变量中的文件(cygwin)

system("cygstart $dirname/$oldfile") ; 

然后它给了我重新命名图片的选项。它虽然是抛出错误,而不是重命名图片。

Use of uninitialized value $oldfile in concatenation (.) or string at ./rename_image.pl line 29, <STDIN> line 6. 

oldfile是一个全局变量,函数应该看变量。

#!/usr/bin/perl 
# 
use strict ; 
use warnings ; 

my $oldfile; 
my $new_name; 
my $dirname = "/cygdrive/c/Users/walt/Desktop/iphonepics/bunk_box/"; 
opendir(DIR, $dirname) or die "Cannot open dir: $!"; 

my @files = readdir(DIR); 
foreach $oldfile (@files) { 
     system("cygstart $dirname/$oldfile") ; 
     print "Do you want to rename $oldfile ? "; 
     my $input = <STDIN> ; 
     chomp $input ; 
     if($input =~ m/^[y]$/i) { 
       rename_file() ; 
     } else { 
     my $doo = 1 ; 
     } 
} 

sub rename_file { 
     use File::Copy qw(move) ; 
     print "New name:\n" ; 
     my $new_name = <STDIN> ; 
     chomp $new_name ; 
     move "$dirname/$oldfile", "$dirname/$new_name"; 
     return ; 
} 
+0

我们是否看到100%的代码?除了在'foreach'循环中执行rename_file没有可能的方法吗? – DavidO

+0

这与您看到的警告无关,但您是否注意到您的路径将如下所示? ''/ cygdrive/c/Users/walt/Desktop/iphonepics/bunk_box // foobar'(换句话说,你要连接一个以/结尾的字符串,在你的连接中使用另一个/ – DavidO

+0

是的,这是代码和否,它不重命名任何文件,它迄今为止不能按计划运行,另外,没有我没有注意到$ dirname变量中的额外斜线。一个变量 - 以斜线或开头结尾(假设斜线) – capser

回答

1

foreach $oldfile (@files)不会为在顶部声明的$oldfile赋值。这是一个词汇变量,不是全局的,在这种情况下,会为循环范围创建一个新的词汇$oldfile。这是仅有的foreach的特定财产。有关详细信息,请参阅this post

由于$oldfileforeach是一个动态范围内的词汇,它是不可见的子。但是sub看到my $oldfile为文件的静态范围声明。从Private Variables via my()

...与my声明词法变量是完全与外界隐藏,包括任何调用的子程序。如果它是从自己或其他地方调用的相同子例程,则这是真实的 - 每个调用都会获得自己的副本。

这并不意味着在静态封闭的词法范围中声明的my变量将不可见。只有动态范围被切断。例如,...

所以子看到$oldfile在顶部,它可以停留,因为它是在循环之前,初始化。

总而言之,这里简单的“修复”是用our $oldfile替换my $oldfile&dagger;  

但是,为什么要依赖全局变量?为什么不能传递给函数各取所需

foreach my $oldfile (@files) { 
    ... 
    if (...) { 
     rename_file($dirname, $oldfile); 
    ... 
} 

sub rename_file { 
    my ($dirname, $oldfile) = @_; 
    ... 
} 

很好的使用strict已经并宣布一切。然后,您不需要,也不应该有在顶部声明的文件范围的词汇my $oldfile;

当你在一个sub中声明一个变量时,这个名字被隐藏在子作用域之外的同名中。所以你在这里知道什么$oldfile是–它正是你传递给函数的东西。

这样子你的sub也有一个定义良好的接口,并且不依赖于周围代码中的任意值。这对清晰描述范围和模块化至关重要。

更一般地说,使用全局变量,而strict已经到位,宣布的其他事情就像是为维护程序员种植一个矿,或者为自己六个月后的谚语。

我建议也阅读Mark-Jason Dominus的Coping with Scoping


&dagger;一种方式来获得预期的行为是让$oldfile之上的全局变量,所以要么放弃my拖放strict,或our $oldfile更换my $oldfile。我不建议这样做,除非有一个非常具体和坚实的理由才能拥有像全球一样的our $oldfile。见our

+0

这是所有合理的建议,但如果我们看到的代码是OP正在使用的代码的100%,则警告应该是不可能的,因为这意味着'readdir'填充了带有undef条目的'@ files' ,而且,当文件名没有出现在屏幕输出中时,脚本的用户仍然设法对是否移动文件的问题说“Y”。鉴于我们不太可能看到产生此警告的代码,因此很难得出这个答案实际上解决了OP的问题的结论。 – DavidO

+1

@DavidO我为警告添加了解释,谢谢提示。至于“不可能” - 事实并非如此,它只是如此。尝试一下,在声明时给'my $ oldfile'一些值。 – zdim

+0

是的 - 这是整个代码 - 它所做的只是在照片查看器中打开照片。我看这张照片,通过我的iphone拍摄的新照片通常被称为IMG_1234.jpg。如果我喜欢它,我点击是,然后重命名照片。任何剩下的IMG_ *将从目录中删除。 – capser

相关问题