bash shell:更改多个文件名以添加前导零

时间:2014-05-22 23:10:53

标签: bash shell

我有几个使用此模式的文件:prefix.1.*prefix.2.*prefix.3.*等...我希望他们的名字分别更改为prefix.01.*prefix.02.*prefix.03.*等。这样,它们将按名称正确排序,因为集合中已有两位数(例如prefix.27.*)的文件名。

如何使用bash shell中提供的命令来实现?


注意:就在这个问题之后,我不得不处理一个文件列表,例如prefix.1.*prefix.2.*prefix.17.*prefix.157.*(任意,不按顺序编号) ,目的是使用插入正确数量的前导零的通用方式转换为prefix.001.*prefix.002.*prefix.017.*prefix.157.*。如果您遇到这种情况,我强烈建议您遵循以下mklement0 answer更通用的重命名解决方案)提供的一般解决方案。

6 个答案:

答案 0 :(得分:3)

for file in prefix.[0-9].*
do
   mv "$file" "${file/prefix./prefix.0}"
done

答案 1 :(得分:2)

更通用的重命名解决方案,由OP后来的评论提示

使用基于Perl的rename实用程序,它是某些 Linux发行版(例如,Ubuntu)的标准配置。 警告:某些发行版具有util-linux包中同名的不同实用程序。
在OS X上,您可以使用brew install rename通过Homebrew进行安装。

两种解决方案都会动态确定所需的填充宽度


更简单的解决方案,如果文件已按顺序编号仅填充必须执行 [不符合OP的要求 - 请参阅下面的其他解决方案] < / EM>:

printf '%s\n' prefix.[0-9]*.* |                # enumerate files of interest
  sort -t. -n -k2,2 |                          # sort them by the embedded number
    rename -n -N '...01' -e 's/\.\d+\./.$N./'  # rename with appropriate padding
  • -n仅执行干运行,仅显示发生的事情;删除它以执行实际重命名
  • -N '...01'根据输入文件数自动确定适当的零填充的方式指定特殊计数器变量$N的格式。
  • 's/\.\d+\./.$N./'是一个Perl表达式,用适当填充的计数器变量$N替换现有的数字组件。

保留现有数字并仅填充它们的更复杂的解决方案。

在这种情况下,填充宽度来自文件名中嵌入的最大现有数字

# Determine the longest (largest) number contained in the matching filenames...
maxNum=$(printf '%s\n' prefix.[0-9]*.* | sort -nrt. -k2,2 | head -1 | cut -d. -f2)
# ... and derive the padding length from it.
padLength=${#maxNum}

# Perform renaming by zero-padding the *existing* numbers in the filenames.
rename -n -e 's/\.(\d+)\./sprintf(".%0'${padLength}'s.", $1)/e' prefix.[0-9]*.*
  • -n仅执行干运行,仅显示发生的事情;删除它以执行实际重命名
  • 请注意在e命令中使用Perl的s/.../.../标志,该标志允许在替换字符串中使用任意Perl表达式;在这种情况下,sprintf表达式用于填充输入数字;这种方法的功劳属于@AdrianFrühwirth的回答here

总的来说,使用shopt -s extglobprefix.+([0-9]).*可以使匹配的文件名更加健壮;同样,shopt -s nullglob可以更轻松地确定任何文件是否匹配。

答案 2 :(得分:1)

请注意纯bash解决方案,但更简洁(*):

printf '%s\0' prefix.[0-9].* | 
  xargs -0 -I % bash -c 'f="%"; mv "$f" "${f/\./.0}"'

这假设glob prefix.[0-9].*扩展到至少1个实际文件名 如果NO文件可能匹配,请先执行shopt -s nullglob(如果需要,稍后再恢复该shell选项的值)。


效果记录

虽然这比<{3}}更简洁,但由于每个人都会生成一个额外的子shell(bash -c),因此表现更差输入文件名 - 以便能够将文件名分配给变量并在其上使用扩展。


(*)就字符数而言,@R Sahu's solution实际上更短,但缺少循环(以及更少的行)可能会导致此答案被感知< / em>更短。在一天结束时,这个解决方案本身并没有多少 - 除了作为使用xargs 的高级示例之外:

  • printf '%s\0'确保所有匹配的文件名都通过NUL字符传递给管道。作为分隔符。
  • xargs -0然后确保单独识别文件名,即使它们包含嵌入的空格。
  • -I %确保每个输入文件名导致其自己调用后面的命令,其中%个实例替换为手头的文件名。
  • bash -c然后调用子shell(恰好是另一个bash实例的子进程)并评估指定的字符串。

答案 3 :(得分:0)

我找到的最简单的方法就是在bash shell中输入这一行:

for ITER in 1 2 3 4 5 6 7 8 9; do for FILE in prefix."$ITER".*; do mv "$FILE" $(echo "$FILE" | sed 's/prefix.'$ITER'/prefix.0'$ITER'/'); done; done

答案 4 :(得分:0)

另一种方式&gt;&gt;

#!/bin/bash
count=1
for i in $(ls prefix*)
do
Newname=prefix\.$(printf "%02d" $count)\.txt
mv $i $Newname
count=$(($count + 1))
done

答案 5 :(得分:0)

到目前为止,很好的答案。如果所有文件的扩展名都相同。只需使用以下。这里的扩展名是.jpg 您可以将prefix_更改为您选择的前缀。 另外,如果您想要更多的前导零,只需将%02更改为%03,依此类推。

rename -n -e 's/\d+/sprintf("prefix_%02d",$&)/e' -- *.jpg