2011-03-31 108 views
2

我有一個包含50,000多個文件的目錄結構。文件名的格式爲<YYMMDD>-<NNN>.htm需要拼合一個目錄,修改文件名。用bash?

目錄結構

/<category>/<YYYY>/<MM>/

例如:

./Racing/1998/03/980320-001.htm 
./Racing/1998/03/980320-002.htm 
... 
./General/1999/02/990221-001.htm 
./General/1999/02/990221-002.htm 
... 

我想要的文件的扁平列表的形式爲

<category>-<YYYY>-<MM>-<DD>-<NNN>

所以以上是

Racing-1998-03-20-001.htm 
Racing-1998-03-20-002.htm 
... 
General-1999-02-21-001.htm 
General-1999-02-21-002.htm 

我(重新)學習慶典&正則表達式,並希望就如何落實這一些指針。

我知道如何生成路徑列表,但不知道如何應用正則表達式來轉換窗體。我會提前使用find -type f -name "*.htm" | <some goblygook here>

其中<some goblygook here>可能利用xargs ...

感謝。

[編輯3/30下午9點58分]

每答案在下面,我炮製這個腳本。我不能讓xargs工作:

#!/bin/bash 
mkdir ./flat 
find -type f -name "*.htm" | \ 
awk -F'[/]' ' 
BEGIN{OFS="-"} 
{ gsub(/^\.\//,"") ;print "./" $0 " ./flat/" $1,$2, substr($4,3,2),substr($4,5,2),substr($4,8)} 
' | \ 
xargs -p -d "\n" -n 1 cp 

運行這給了我:

$ ./awktest.sh 
mkdir: cannot create directory `./flat': File exists 
cp ./General/1997/05/970525-002.htm ./flat/General-1997-05-25-002.htm ?...y 
cp: missing destination file operand after `./General/1997/05/970525-002.htm ./flat/General-1997-05-25-002.htm' 
Try `cp --help' for more information. 
^C 

複製從輸出的精確cp命令(cp ./General/1997/05/970525-002.htm ./flat/General-1997-05-25-002.htm)和直接粘貼到bash提示符下正常工作。

我試圖搞清楚如何使用-print0find命令,但無法弄清楚如何讓awk使用\0作爲記錄終止(RS="\0"是行不通的)。我認爲這個問題與換行符有關,但我很茫然!

+0

值得指出的是,有一個很好的理由說明爲什麼目錄結構是這樣的,而不是平坦的 - 如果最終在一個目錄中有太多的文件,很多文件系統性能不佳,而且使用標準工具的目錄變得很笨重。 – caf 2011-03-31 05:53:40

+0

@caf - 謝謝。實際上,我將其作爲亞馬遜S3的測試來完成,在這裏我想要在我的存儲桶中包含許多文件。 – tig 2011-03-31 06:07:35

回答

1

通常沒有必要使用sedawk存在。這是另一種答案不叉額外sed過程

find -type f -name "*.htm" | awk -F'[/]' 'BEGIN{OFS="-"}{ gsub(/^\.\//,"") ;print $1,$2, substr($4,3,2),substr($4,5,2),substr($4,8) }' 

編輯,你可以做你的cpawk

find -type f -name "*.htm" | awk -F'[/]' 'BEGIN{OFS="-"}{ 
    gsub(/^\.\//,"") 
    source = $1 OFS $2 OFS substr($4,3,2) OFS substr($4,5,2) OFS substr($4,8) 
    destination = <create your destination here> 
    command = "cp "source" "destination 
    system(command) 
}' 
+0

這個工作也是。我喜歡它只涉及一種工具的事實。如果我正確地理解了這一點,-F'[/]'告訴awk分隔符是/和OFS =「 - 」表示「當輸出參數時在它們之間放置」。對? – tig 2011-03-31 04:01:17

+0

@tig,是的。不,它涉及2個工具(find + awk):)。如果你有bash 4及以上版本,你可以使用bash而不用外部工具。 :) – kurumi 2011-03-31 04:13:09

+0

我的意思是除了找到1個工具。 – tig 2011-03-31 04:16:56

3

find -type f -name "*.htm" | sed '[email protected]^./@@g;[email protected]/@[email protected]' | awk -F'-' '{print $1 "-" $2 "-" $3 "-" substr($4, 5, 2) "-" $5}'

sed & awk對於文本操作非常有用。

+0

這是翻轉真棒。有用。把我吹走你不需要測試它。無論如何,我想了解它,所以我希望你不會介意回答更多的問題。首先,我無法找到在sed命令中@做什麼的文檔;那裏發生了什麼? – tig 2011-03-31 03:10:58

+0

您可能會看到一些sed命令,如:sed's/aaa/bbb/g'其中'/'用於分隔字符串。但是當你的字符串中有'/'時,你需要使用其他字符,在這裏我使用'@',它可以是任何其他字符。 – 2011-03-31 03:12:47

+0

明白了。說得通。 – tig 2011-03-31 03:15:04

-1

將文件複製這樣:

eval "`find -type f -name "*.htm" |awk -F/ '{print "cp " $0 " " $2 "-" $3 "-" $4 "-" substr($5,5) ";" }'`" 
+0

不必使用'eval' – kurumi 2011-03-31 03:27:37

2

我不得不調整公認的答案爲我工作:

find -type f -name "*.png" | awk -F'[/]' 'BEGIN{OFS="_"}{ 
    gsub(/^\.\//,"") 
    source = "source root folder" $1 "/" $2 "/" $3 
    destination = "destination folder" $1 OFS $2 OFS $3 
    command = "cp "source" "destination 
    system(command) 
}'