
我必須使用命令rename
(使用正規表示式)重命名一組檔案。經過一番嘗試,我無法找到獲得預期結果的表達式。
我有一個這樣的文件模式:
字首_一些名稱_other.txt
所有檔案均以“ prefix_
”字串開頭並以“ ”結尾_other.txt
,並且一些名稱部分可以由多個(字母數字)單字組成,並用底線分隔。所以可以有:
prefix_one_name_other.txt
prefix_this_is_my_name_1_this1_other.txt
我需要像這樣重命名檔案名稱:
其他_同名_約會時間 other_this-is-my-name-1-this1_約會時間
換句話說:
- 需要刪除“
prefix
”(保留底線) - 「
other
」標記位於檔案名稱的開頭 - 在一些名稱, 將底線 (_) 轉換為破折號 (-)
- 檔案名稱末尾的底線(之後一些名稱)必須保留
- 需要刪除
.txt
擴展名,替換為約會時間。
我嘗試過的:
rename 's/fw_([a-z]+)_(\d)_(\w+\d)_(\w+)\.txt/$4_$1-$2-$3_'$datahora'/' *.txt
$datahora
有約會時間值(已測試)。這按預期工作
prefix_name_1_gnt1_other.txt
但不與
prefix_other_name_2_gnt2_other.txt
我哪裡做錯了?我還能怎麼做到這一點?
我已經懸而未決了,因為現在我無法找到適用於我擁有的所有檔案名稱的正規表示式。我知道,字串中的第一個元素始終是該prefix
部分,最後一個元素是other.txt
字串的一部分。因此可以將字串拆分為數組,並取得建構新名稱所需的項目。事實上,類似的事情。
datahora="20140718-080000"
arrfiles=( *.txt )
for curfile in ${arrfiles[*]}
do
arrparts=( ${curfile//_/ } )
numitems=${#arrparts[*]}
newname=""
for (( c=1; c<numitems-1; c++ ))
do
newname+="${arrparts[c]}-"
done
newname=${newname%-}
arrparts[numitems-1]=${arrparts[numitems-1]/.txt/}
newname="${arrparts[numitems-1]}_${newname}_$datahora"
echo "$curfile pasa a $newname"
mv ${curfile} ${newname}
done
以這種方式完成後,我再次嘗試@peterph建議,最後完成了一些重命名正規表示式組合。有點像這樣:
rename 's/_/-/g' *.txt
rename 's/^fw-(.*)-([^-]*)(\.txt)/$2.$1$3/' *.txt
rename 's/(\w+)\.(.*)(\.txt)/$1_$2_'$datahora'/' *.txt
我不確定最好的方法是什麼。在我看來,正規表示式變體似乎更優雅,但我需要三個重命名操作(訪問磁碟三次)才能完成工作,而該array
變體僅寫入磁碟一次。
您對這兩種解決方案有何看法?
再次感謝。
答案1
除非你rename
可以接受多個替換命令和檔案名稱的根 ( some_name
) 可能包含多個下劃線,您必須分兩步驟執行此操作:a) 用破折號替換下劃線,b) (重新)移動檔案名稱中的區塊。
您正在尋找的正規表示式可以是例如:
rename 's/_/-/g' *.txt
rename 's/^prefix-(.*)-([^-]*).txt$/$2_$1_'$DATETIME'/' *txt
第一個將底線轉換為破折號,而後者則交換根和後綴並將DATETIME
環境變數的內容附加到名稱中。當然,並省略前綴和擴展名。
該[^-]*
部分符合任何不包含破折號的字串。如果後綴始終相同,您可以將其逐字放在那裡,就像前綴一樣(反之亦然 - 如果前綴可能不同,請使用^[^-]*-
將其匹配為不包含位於檔案開頭之間的破折號的任何字串名稱和(因此)第一個破折號)。
如果您rename
支援多個命令,只需將它們連接起來即可:
rename 's/_/-/g;s/^prefix-(.*)-([^-]*).txt$/$2_$1_'$DATETIME'/' *txt