繁体   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