2013-05-01 27 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