AWK,SED,REGEX重命名文件

问题描述 投票:8回答:6

我只是学习使用REGEX,AWK和SED。我目前有一组我想要重命名的文件 - 它们都位于一个目录中。

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

01._HORRIBLE_HISTORIES_S2.mp4
02._HORRIBLE_HISTORIES_S2.mp4

我想将它们重命名为HORRIBLE_HISTORIES_s01e01.mp4 - 其中e01是从第一列收集的。我知道我想从第一列中获取“01”,将其填入变量中,然后将其粘贴到每个文件名中的S2之后,同时我想将其从文件名的开头与“。”一起删除。 _“,另外我想将”S2“改为”s02“。

如果有人会这么善良,你能帮助我用awk / sed写一些东西并解释一下我可以从中学习的程序吗?

regex sed awk filenames renaming
6个回答
8
投票
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,...)。
  • 首先,使用0将“_S {number}”中的数字左边填充为2位数(即,如果该数字还没有2位数,则仅预设0)并存储在变量si(季节索引)中;如果可以始终预先添加0,awk“程序”可以简化为:{ print $3 "_" $4 "_s0" substr($5,2) "e" $1 "." $6 }
  • 然后重新排列结果以及剩余的标记以形成所需的文件名。

请注意echo之前的mv,以便您安全地预览生成的命令 - 将其删除以执行实际重命名。

替代方案:使用正则表达式的纯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只是前置。

如上所述,您需要在echo之前删除mv以执行实际重命名。


9
投票

根据模式重命名多个文件的常用方法是使用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,它会将所有文件重命名为real。

rename通常在Linux上可用(包util-linux)。这里有一个similar discussion,其中有关于查找/安装正确命令的更多详细信息。


2
投票

你可以用几乎纯粹的bash(使用variable expansion)来做到这一点:

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

如果此命令的输出符合您的需要,您可以从循环中删除echo,或者更简单地(如果您的上一个命令是上述命令)问题:!! | bash


0
投票

将文件名字符串转换为文本文件,然后使用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

0
投票

如果你愿意使用gawk,那么正则表达式匹配真的很方便。我发现这种基于管道的解决方案比担心循环结构更好一些。

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

为了便于阅读,我用椭圆替换了正则表达式和mv命令。

  • 第1行列出了当前目录中的所有文件名,每行一行,并将其传递给gawk命令。
  • 第2行运行正则表达式匹配,将捕获的组分配给数组变量a。该动作通过printf将其转换为我们所需的命令,sh本身通过管道传输到mklement0来执行。
  • 第3行关闭了当我们开始向它添加东西时隐式打开的shell。

那么你只需填写你的正则表达式和命令语法(借用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") }' )。例如(LIVE CODE WARNING):

| "sh"

要预览该命令(如您所愿),您只需从第二行删除ls | while read file; do newfile=`echo $file | awk -F . '{print $1 "." $2 "." $4}'`; echo $newfile; mv $file $newfile; done; 即可。


0
投票

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

qazxswpoi
© www.soinside.com 2019 - 2024. All rights reserved.