如何在 Bash 中将文件名中的填充数字清零?
使用 Bash 重命名以下形式的文件的最佳方法是什么:
(foo1, foo2, ..., foo1300, ..., fooN)
使用零填充的文件名:
(foo00001, foo00002, ..., foo01300, ..., fooN)
What is the best way, using Bash, to rename files in the form:
(foo1, foo2, ..., foo1300, ..., fooN)
With zero-padded file names:
(foo00001, foo00002, ..., foo01300, ..., fooN)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
要在文件名中添加数字(此处为带字母扩展名的数字文件名,例如 1.abc):
解释
`echo ... $2}\`
(上面的反斜杠 \,只是将单行拆分为两行以提高可读性)[0-9]*.[az]*< /code>
$f
) 以将其传递给awk
-F.
:awk
字段分隔符、句点 (.
):如果匹配,则将文件名分隔为两个字段($1
= 数字;$2
= 扩展名),$1
,数字部分)打印为 4 位数字 (%04d
),然后打印句点,然后打印第二个字段($2
:扩展名)作为字符串 (%s
)。 最后,所有这些都分配给$tmp
变量$f
) 移动到新文件名 ($tmp
)To left-pad numbers in filenames (here numeric file names with alphabetic extensions, e.g. 1.abc):
Explanation
`echo ... $2}\`
(The backslash, \, immediately above just splits that one-liner over two lines for readability)[0-9]*.[a-z]*
$f
) to pass it toawk
-F.
:awk
field separator, a period (.
): if matched, separates the file names as two fields ($1
= number;$2
= extension)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$f
) to the new filename ($tmp
)纯 Bash,除了“mv”之外没有外部进程:
Pure Bash, no external processes other than 'mv':
我使用的单行命令是这样的:
PATTERN 可以是例如:
%04d.${f#*.}
(保留原始文件扩展名)使用%04d.jpg
photo_$(basename $f .${f#*.})_%04d.${f#*.}
您可以过滤要重命名的文件,例如
ls *.jpg | ...
您可以使用变量
f
(文件名)和i
(计数器)。对于你的问题,正确的命令是:
The oneline command that I use is this:
PATTERN can be for example:
%04d.${f#*.}
(keep original file extension)photo_%04d.${f#*.}
(keep original extension)%04d.jpg
photo_$(basename $f .${f#*.})_%04d.${f#*.}
You can filter the file to rename with for example
ls *.jpg | ...
You have available the variable
f
that is the file name andi
that is the counter.For your question the right command is:
以下内容将完成此操作:
编辑:更改为使用 ((i=1,...)),谢谢 mweerden!
The following will do it:
EDIT: changed to use ((i=1,...)), thanks mweerden!
我的解决方案替换了数字,字符串中的所有位置
您可以轻松尝试它,因为它只打印转换后的文件名(不执行文件系统操作)。
说明:
循环遍历文件列表
循环:
for f in * ; do ;done
,列出所有文件并将每个文件名作为$f
变量传递到循环体。从字符串中获取数字
使用 echo $f | sed 我们将变量
$f
通过管道传递给sed
程序。在命令
sed 's/[^0-9]*//g'
中,[^0-9]*
部分带有修饰符^
指示匹配数字 0-9(不是数字)的相反数字,然后用空替换//
将其删除。 为什么不直接删除[az]
呢? 因为文件名可以包含点、破折号等。因此,我们删除所有内容(不是数字)并得到一个数字。接下来,我们将结果分配给
number
变量。 请记住不要在赋值中添加空格,例如number = ...
,因为您会得到不同的行为。我们将命令的执行结果分配给变量,用反引号`包裹命令。
零填充
命令
printf "%04d" $number
将数字格式更改为 4 位数字,如果数字少于 4 位,则添加零。将数字替换为零填充数字
我们再次使用
sed
以及诸如s/substring/replacement/
之类的替换命令。 为了解释我们的变量,我们使用双引号并以${number}
的方式替换我们的变量。上面的脚本只是打印转换后的名称,所以,让我们做实际的重命名工作:
希望这对某人有帮助。
我花了几个小时才弄清楚这一点。
My solution replaces numbers, everywhere in a string
You can easily try it, since it just prints transformed file names (no filesystem operations are performed).
Explanation:
Looping through list of files
A loop:
for f in * ; do ;done
, lists all files and passes each filename as$f
variable to loop body.Grabbing the number from string
With
echo $f | sed
we pipe variable$f
tosed
program.In command
sed 's/[^0-9]*//g'
, part[^0-9]*
with modifier^
tells to match opposite from digit 0-9 (not a number) and then remove it it with empty replacement//
. Why not just remove[a-z]
? Because filename can contain dots, dashes etc. So, we strip everything, that is not a number and get a number.Next, we assign the result to
number
variable. Remember to not put spaces in assignment, likenumber = …
, because you get different behavior.We assign execution result of a command to variable, wrapping the command with backtick symbols `.
Zero padding
Command
printf "%04d" $number
changes format of a number to 4 digits and adds zeros if our number contains less than 4 digits.Replacing number to zero-padded number
We use
sed
again with replacement command likes/substring/replacement/
. To interpret our variables, we use double quotes and substitute our variables in this way${number}
.The script above just prints transformed names, so, let's do actual renaming job:
Hope this helps someone.
I spent several hours to figure this out.
如果
N
不是先验固定的:In case
N
is not a priori fixed:我有一个更复杂的情况,其中文件名有后缀和前缀。 我还需要对文件名中的数字进行减法。
例如,我希望
foo56.png
变为foo00000055.png
。如果您正在做更复杂的事情,我希望这会有所帮助。
I had a more complex case where the file names had a postfix as well as a prefix. I also needed to perform a subtraction on the number from the filename.
For example, I wanted
foo56.png
to becomefoo00000055.png
.I hope this helps if you're doing something more complex.
此答案源自 Chris Conway 接受的答案,但假设您的文件具有扩展名(与 Chris 的答案不同)。 只需将这个(相当长的)一行粘贴到您的命令行中即可。
可选附加信息
此脚本将重命名
要在您的计算机上测试它,只需将这一行粘贴到空目录中即可。
这将删除目录的内容,创建上例中的文件,然后进行批量重命名。
对于那些不需要一行的人,缩进的脚本看起来像这样。
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.
OPTIONAL ADDITIONAL INFO
This script will rename
To test it on your machine, just paste this one liner into an EMPTY directory.
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.
这是一个快速解决方案,假设固定长度前缀(您的“foo”)和固定长度填充。 如果您需要更大的灵活性,也许这至少是一个有用的起点。
Here's a quick solution that assumes a fixed length prefix (your "foo") and fixed length padding. If you need more flexibility, maybe this will at least be a helpful starting point.
这不是纯粹的 bash,但使用 Perl 版本的
rename
更容易:其中
's/\d+/sprintf("%05d",$&)/e'
是 Perl 替换正则表达式。\d+
将匹配第一组数字(至少一个数字)sprintf("%05d",$&)
将把匹配的数字传递给 Perl 的sprintf
和%05d
将填充到五位数字It's not pure bash, but much easier with the Perl version of
rename
:Where
's/\d+/sprintf("%05d",$&)/e'
is the Perl replace regular expression.\d+
will match the first set of numbers (at least one number)sprintf("%05d",$&)
will pass the matched numbers to Perl'ssprintf
, and%05d
will pad to five digits