Bash 正则表达式重命名文件集

Bash 正则表达式重命名文件集

我必须使用命令rename(带正则表达式)重命名一组文件。经过几次尝试,我找不到获得预期结果的表达式。

我有一个这样的文件模式:

字首_某个名字_其他.txt

所有文件都以“ prefix_”字符串开头,以“ ”结尾_other.txt,并且某个名字部分可以由下划线分隔的多个(字母数字)单词组成。因此,可以有:

prefix_one_name_other.txt
prefix_this_is_my_name_1_this1_other.txt

我需要重命名文件名,如下所示:

other_one-name_约会时间
other_这是我的名字-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

相关内容