60

使用 Bash 以以下形式重命名文件的最佳方法是什么:

(foo1, foo2, ..., foo1300, ..., fooN)

使用零填充文件名:

(foo00001, foo00002, ..., foo01300, ..., fooN)
4

10 回答 10

74

它不是纯 bash,但使用 Perl 版本的rename:

rename 's/\d+/sprintf("%05d",$&)/e' foo*

's/\d+/sprintf("%05d",$&)/e'Perl 替换正则表达式在哪里。

  • \d+将匹配第一组数字(至少一个数字)
  • sprintf("%05d",$&)将匹配的数字传递给 Perl's sprintf%05d并将填充到五位数
于 2010-12-30T10:23:45.687 回答
40

如果N不是先验固定的:

for f in foo[0-9]*; do
  mv "$f" "$(printf 'foo%05d' "${f#foo}")"
done
于 2008-09-11T03:47:46.070 回答
21

我有一个更复杂的情况,文件名有后缀和前缀。我还需要从文件名中减去数字。

例如,我想foo56.png成为foo00000055.png.

如果您正在做更复杂的事情,我希望这会有所帮助。

#!/bin/bash

prefix="foo"
postfix=".png"
targetDir="../newframes"
paddingLength=8

for file in ${prefix}[0-9]*${postfix}; do
  # strip the prefix off the file name
  postfile=${file#$prefix}
  # strip the postfix off the file name
  number=${postfile%$postfix}
  # subtract 1 from the resulting number
  i=$((number-1))
  # copy to a new name with padded zeros in a new folder
  cp ${file} "$targetDir"/$(printf $prefix%0${paddingLength}d$postfix $i)
done
于 2010-09-13T11:54:54.573 回答
7

我使用的单行命令是这样的:

ls * | cat -n | while read i f; do mv "$f" `printf "PATTERN" "$i"`; done

例如,模式可以是:

  • 使用增量计数器重命名:(%04d.${f#*.}保留原始文件扩展名)
  • 使用带前缀的增量计数器重命名:(photo_%04d.${f#*.}保留原始扩展名)
  • 使用增量计数器重命名并将扩展名更改为 jpg:%04d.jpg
  • 使用带有前缀和文件基名的增量计数器重命名:photo_$(basename $f .${f#*.})_%04d.${f#*.}
  • ...

您可以过滤要重命名的文件,例如ls *.jpg | ...

您可以使用f作为文件名的变量,即i计数器。

对于您的问题,正确的命令是:

ls * | cat -n | while read i f; do mv "$f" `printf "foo%d05" "$i"`; done
于 2017-08-08T13:22:17.380 回答
6

To left-pad numbers in filenames:

$ ls -l
total 0
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 010
-rw-r--r-- 1 victoria victoria 0 Mar 28 18:09 050
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 050.zzz
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 10
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 1.zzz

$ for f in [0-9]*.[a-z]*; do tmp=`echo $f | awk -F. '{printf "%04d.%s\n", $1, $2}'`; mv "$f" "$tmp"; done;

$ ls -l
total 0
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 0001.zzz
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 0050.zzz
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 010
-rw-r--r-- 1 victoria victoria 0 Mar 28 18:09 050
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 10

Explanation

for f in [0-9]*.[a-z]*; do tmp=`echo $f | \
awk -F. '{printf "%04d.%s\n", $1, $2}'`; mv "$f" "$tmp"; done;
  • note the backticks: `echo ... $2}\` (The backslash, \, immediately above just splits that one-liner over two lines for readability)
  • in a loop find files that are named as numbers with lowercase alphabet extensions: [0-9]*.[a-z]*
  • echo that filename ($f) to pass it to awk
  • -F. : awk field separator, a period (.): if matched, separates the file names as two fields ($1 = number; $2 = extension)
  • format with printf: print first field ($1, the number part) as 4 digits (%04d), then print the period, then print the second field ($2: the extension) as a string (%s). All of that is assigned to the $tmp variable
  • lastly, move the source file ($f) to the new filename ($tmp)
于 2019-03-29T01:07:23.197 回答
5

纯 Bash,除了 'mv' 没有外部进程:

for file in foo*; do
  newnumber='00000'${file#foo}      # get number, pack with zeros
  newnumber=${newnumber:(-5)}       # the last five characters
  mv $file foo$newnumber            # rename
done
于 2009-02-03T08:43:45.170 回答
2

以下将做到这一点:

for ((i=1; i<=N; i++)) ; do mv foo$i `printf foo%05d $i` ; done

编辑:改为使用 ((i=1,...)),谢谢mweerden

于 2008-09-11T03:41:38.737 回答
1
于 2019-02-26T15:17:29.210 回答
1

This answer is derived from Chris Conway's accepted answer but assumes your files have an extension (unlike Chris' answer). Just paste this (rather long) one liner into your command line.

for f in foo[0-9]*; do mv "$f" "$(printf 'foo%05d' "${f#foo}" 2> /dev/null)"; done; for f in foo[0-9]*; do mv "$f" "$f.ext"; done;

OPTIONAL ADDITIONAL INFO

This script will rename

foo1.ext    > foo00001.ext
foo2.ext    > foo00002.ext
foo1300.ext > foo01300.ext

To test it on your machine, just paste this one liner into an EMPTY directory.

rm * 2> /dev/null; touch foo1.ext foo2.ext foo1300.ext; for f in foo[0-9]*; do mv "$f" "$(printf 'foo%05d' "${f#foo}" 2> /dev/null)"; done; for f in foo[0-9]*; do mv "$f" "$f.ext"; done;

This deletes the content of the directory, creates the files in the above example and then does the batch rename.

For those who don't need a one liner, the script indented looks like this.

for f in foo[0-9]*;
  do mv "$f" "$(printf 'foo%05d' "${f#foo}" 2> /dev/null)";
done;

for f in foo[0-9]*;
  do mv "$f" "$f.ext";
done;
于 2021-09-03T01:59:06.040 回答
0

这是一个快速的解决方案,它假设一个固定长度的前缀(你的“foo”)和固定长度的填充。如果您需要更大的灵活性,也许这至少是一个有用的起点。

#!/bin/bash

# some test data
files="foo1
foo2
foo100
foo200
foo9999"

for f in $files; do
    prefix=`echo "$f" | cut -c 1-3`        # chars 1-3 = "foo"
    number=`echo "$f" | cut -c 4-`         # chars 4-end = the number
    printf "%s%04d\n" "$prefix" "$number"
done
于 2008-09-11T03:43:43.677 回答