2013-05-01 45 views
1

我想加载目录中的所有图片并将它们保存到数组中。将目录中的图片加载到数组中

@files = `ls $ARGV[0] | grep -i -E jpe?g|gif|png$`; 

此行给我一个错误:Final $ should be \$ or $name

@files = `ls $ARGV[0] | grep -i -E \'jpe?g|gif|png$\'`; 

这行工作,但还加载图片“img.jpg.bmp”我这不是我想要的,甚至负荷目录,这是次要的,但也是不好的。我究竟做错了什么?

+0

+1 [您的评论](http://stackoverflow.com/questions/16317221/load-pictures-from-directory-into-array#评论233365344_16317351)*“为什么使用外壳如此伤心?”* – fedorqui 2013-05-01 12:32:00

回答

0

使用shell读取目录或grep是种悲哀

use autodie; 
opendir my $dir, $ARGV[0]; 
my @files = grep !/\A\.\.?\z/ && /\.(?:jpe?g|gif|png)\z/, readdir $dir; 
closedir $dir; 

(我们必须manualy过滤掉..。当前目录.和父目录\A就像^\z有点像$,但始终匹配在字符串末尾)

的问题在于它具有双引号字符串的插值语义。 $总是表示下一个单词或字符是变量名称(正则表达式除外)。 $`将是prematch变量,但Perl很聪明,看到你不想要。您的错误信息提出的解决方案是逃避$

`grep -i -E jpe?g|gif|png\$` # … and it meant this. 
# It still thinks gif and png are commands 
`grep -i -E '(jpe?g|gif|png)\$'` # regex correctly quoted on shell level 

用单引号周围仅是外壳上的水平有帮助的,而不是在Perl的水平,其中错误消息的发源地。

在正则表达式中,行结束声明$只是一个普通原子,如p[abc]。它不是运营商,不像()|[]。因此你必须强制正确的优先与parens。看看我提出的Perl解决方案中的正则表达式在上面是如何完成的。

+0

谢谢,工作:)但是...为什么使用外壳如此伤心? – chriemmy 2013-05-01 11:59:04

+0

@chriemmy使用Perl构建的内容更加冗长,但它只使用一个进程而不是三个(→性能)。使用Perl构建更安全:考虑将'$ ARGV [0]'作为'dir with spaces'或'; rm -rf *;回声pwned.jpg'。使用Perl内置模块和模块更便于携带。 Pure-Perl代码可以在Linux,OSX和Windows上运行,无需修改。 – amon 2013-05-01 12:13:03

2

您还可以使用glob函数获取文件列表并使用grep对其进行过滤。例如:

my(@files) = grep { /\.(?:jpe?g|gif|png)\z/ } glob '"*"'; 

或者干脆:

my(@files) = glob '"*.jpeg" "*.jpg" "*.gif" "*.png"'; 
+1

怎么样'glob qq(“$ ARGV [0]/*。{jpeg,jpg,gif,png}”)'? (虽然如果目录名包含双引号,这将会中断,因为现在你的解决方案,你必须将'chdir'放入'$ ARGV [0]'目录以使glob工作) – amon 2013-05-01 12:16:41