簡體   English   中英

AWK,SED,REGEX重命名文件

[英]AWK, SED, REGEX to rename files

我只是在學習使用REGEX,AWK和SED。 我目前有一組要重命名的文件-它們都位於一個目錄中。

命名模式是一致的,但是我想重新排列文件名,這里是格式:

01._HORRIBLE_HISTORIES_S2.mp4
02._HORRIBLE_HISTORIES_S2.mp4

我想將它們重命名為HORRIBLE_HISTORIES_s01e01.mp4-從第一列中收集e01。 我知道我想從第一列中獲取“ 01”,將其填充到變量中,然后將其粘貼到每個文件名的S2之后,與此同時,我想從文件名的開頭將其與“一起刪除”。 _”,此外,我想將“ S2”更改為“ s02”。

如果有人那么善良,您能幫我用awk / sed編寫一些東西並解釋該過程,以便我可以從中學習嗎?

for f in *.mp4; do 
  echo mv "$f" \
    "$(awk -F '[._]' '{ si = sprintf("%02s", substr($5,2)); 
                          print $3 "_" $4 "_s" si "e" $1 "." $6 }' <<<"$f")"
done 
  • 循環遍歷所有*.mp4文件。
  • 將每個重命名為awk命令的結果,該結果通過命令替換( $(...) )提供。
  • awk命令通過將輸入文件名拆分為令牌. 或“ _”(這使第一個令牌可用$1 ,第二個令牌可用$2 ,...)。
  • 首先,將“ _S {number}”中的數字用0左填充到2位數字(即,僅當數字還沒有2位數字時才添加0 )並存儲在變量si (季節索引)中; 如果可以始終始終添加0 ,則可以將awk“程序”簡化為: { print $3 "_" $4 "_s0" substr($5,2) "e" $1 "." $6 } { print $3 "_" $4 "_s0" substr($5,2) "e" $1 "." $6 }
  • 然后將結果與其余標記重新排列以形成所需的文件名。

mv之前記下echo ,以使您可以安全地預覽生成的命令-刪除它以執行實際的重命名。

替代方案 :使用正則表達式的純bash解決方案:

for f in *.mp4; do 
  [[ $f =~ ^([0-9]+)\._([^.]+)_S([^.]+)\.(.+)$ ]]
  echo mv "$f" \
"${BASH_REMATCH[2]}_s0${BASH_REMATCH[3]}e${BASH_REMATCH[1]}.${BASH_REMATCH[4]}"
done 
  • 使用bash的正則表達式匹配運算符=~和捕獲組( (...)的子字符串)與每個文件名匹配並提取感興趣的子字符串。
  • 匹配結果被存儲在特殊數組變量$BASH_REMATCH ,與元件0包含整個比賽, 1含有什么第一捕獲組,火柴2第二,等等。
  • 然后, mv命令的目標參數按所需順序組合捕獲組匹配項。 請注意,在這種情況下,為簡單起見,我將s{number}的零填充設為無條件-只是在前面加上了0

如上所述,您需要在mv之前刪除echo以執行實際的重命名。

根據模式重命名多個文件的常用方法是使用Perl命令rename 它使用Perl正則表達式,功能非常強大。 使用-n -v來測試模式而不接觸文件:

$ rename -n -v 's/^(\d+)._(.+)_S2\.mp4/$2_s02e$1.mp4/' *.mp4
01._HORRIBLE_HISTORIES_S2.mp4 renamed as HORRIBLE_HISTORIES_s02e01.mp4
02._HORRIBLE_HISTORIES_S2.mp4 renamed as HORRIBLE_HISTORIES_s02e02.mp4

使用括號將字符串捕獲到變量$1 (第一次捕獲), $2 (第二次捕獲)等中:

  • ^(\\d+)在文件名的開頭捕獲數字(到$1)
  • ._(.+)_S2\\.mp4捕獲.__S2.mp4之間的所有內容(成$2
  • $2_s02e$1.mp4將新文件名與捕獲的數據組合起來

對結果滿意后,從命令中刪除-n ,它將重命名所有文件。

rename往往是默認選項在Linux(包util-linux )。 在SO上也有類似的討論 ,其中包含有關查找/安裝正確命令的更多詳細信息。

您可以使用幾乎純bash (具有可變的擴展 )來做到這一點:

for f in *mp4 ; do
  newfilename="${f:5:20}_s01e${f:1:2}.mp4"
  echo mv $f $newfilename
done

如果此命令的輸出適合您的需要,則可以從循環中刪除echo ,或者更簡單地(如果您的最后一個命令是上述命令)發出以下問題: !! | bash !! | bash

使文件名字符串成為文本文件,然后使用loop和awk重命名文件。

while read oldname; do
  newname=$(awk -F'.' '{ print substr($2, 2) "_e" $1 "." $3 }' <<< ${oldname} | \
        awk -F'_' '{ print $1 "_s0" substr($2, 2) $3 }');
  mv ${oldname} ${newname};
done<input.txt

如果您願意使用gawk ,則正則表達式匹配確實非常有用。 我發現這種基於管道的解決方案比擔心循環構造要好得多。

ls -1 | \
    gawk 'match($0, /.../, a) { printf ... | "sh" } \
    END { close("sh") }'

為了便於閱讀,我用省略號替換了regex和mv命令。

  • 第1行列出了當前目錄中的所有文件名,每行一行,並將其通過管道傳送到gawk命令。
  • 第2行運行regex匹配,將捕獲的組分配給數組變量a 該動作使用printf其轉換為我們所需的命令,該命令本身通過管道傳遞給sh以執行。
  • 第3行關閉了當我們開始向其管道傳遞內容時隱式打開的外殼。

因此,您只需填寫正則表達式和命令語法(從mklement0借用)。 例如( LIVE CODE WARNING ):

ls -1 | \
    gawk 'match($0, /^([0-9]+)\._([^.]+)_S([^.]+)\.(.+)$/, a) { printf "mv %s %s_s0%se%s.%s\n",a[0],a[2],a[3],a[1],a[4] | "sh" } \
    END { close("sh") }'

要預覽該命令(如您所願),您只需刪除| "sh" 第二行的| "sh"

使用AWK。 用第一部分,第二部分和第四部分重命名文件

ls | while read file; do newfile=`echo $file | awk -F . '{print $1 "." $2 "." $4}'`; echo $newfile;  mv $file $newfile; done;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM