在文件名末尾添加连续数字 - Shell脚本

4

我正在尝试在重命名脚本中向文件名末尾添加四位数字序列。但我遇到的问题是,它只能填充第一个文件,并且添加的数字不是按顺序的。以下是我的脚本:

起始文件名:

FILE-1.png
FILE-5.png
FILE-14.png
FILE-99.png
FILE-167.png
FILE-199.png
FILE-278.png
FILE-455.png

脚本:

a=`printf '%04d' "1"`

cd /${1-$PWD}

for i in *.png;
    do mv $i `printf output.%04d.$a.png $(echo $i | sed 's/[^0-9]*//g')`;
    let a=a+1 
done

编辑: 我稍微修改了脚本,包含了顶部的fmt变量。但是我仍希望它按照第一组数字的数值顺序来命名第二组数字,就像下面我的期望输出那样。

fmt=output.%04d
n=1

cd /${1-$PWD}

for i in *.png;
    do mv $i `printf $fmt.%04d.png $(echo $i | sed 's/[^0-9]*//g') "$n"`;
    n=$((n+1))
done

我的新输出:

output.0001.0001.png
output.0005.0007.png
output.0014.0002.png
output.0099.0008.png
output.0167.0003.png
output.0199.0004.png
output.0278.0005.png
output.0455.0006.png

原始输出:

output.0001.0001.png
output.0005.7.png
output.0014.2.png
output.0099.8.png
output.0167.3.png
output.0199.4.png
output.0278.5.png
output.0455.6.png

希望结果如下:

output.0001.0001.png
output.0005.0002.png
output.0014.0003.png
output.0099.0004.png
output.0167.0005.png
output.0199.0006.png
output.0278.0007.png
output.0455.0008.png

一如既往,非常感谢您的帮助!


2
不确定为什么有人会对此进行负投票。它具备了一个好问题的所有要素——输入、期望输出和实际输出,甚至还尝试编写了解决方案。 - ghoti
2个回答

1
要在文件名末尾添加顺序编号,您可以使用以下批处理脚本。
@echo off
setlocal EnableDelayedExpansion
set suffix=100
for /F "delims=" %%i IN ('dir /B *.txt') do (
    set /A suffix+=1
    ren "%%i" "%%~ni_!suffix!.txt"

启用延迟扩展以在循环内获取后缀变量的即时值。

%%~ni用于获取无扩展名的文件名。要了解更多类似选项,只需使用'for/?'

参考自StackOverflow问题


1

所以..你正在使用 printf 进行格式化。这是一个好的开始。但是你没有一致地使用它。那部分没有被格式化..为什么不就直接格式化呢?

#!/bin/sh

fmt="output.%04d.%04d.png"

cd /${1-$PWD}

n=1
for file in *.png; do
    fn="${file%.*}"; fn="${fn#*-}"
    mv "$file" "$(printf "$fmt" "$fn" "$n")"
    n=$((n+1))
done

请注意循环中的第一行代码只是从$file中剥离出数字,首先从点到结尾删除所有内容,然后从开头到破折号删除所有内容。如果您的文件格式与问题中不同,您需要进行调整。
哦,感恩节快乐 :-)

根据评论更新

上面的*.png扩展名会按字母顺序排序,这意味着你的FILE-5.png会在FILE-455.png之后,以此类推。

许多工具可以帮助您获得“自然”排序顺序。特别是,如果您使用Linux,则您的lssort可能来自GNU coreutils,这意味着您可以使用ls -vsort -V来获得自然排序顺序。但是,您没有指定您是否使用Linux,而且解析ls是一个坏主意。但bash的内部模式匹配和路径名扩展不处理自然排序。

这种特定情况下,由于您(至少在问题中)正在处理高度可预测格式的文件名,因此我们可以安全地解析ls输出并使用命令行工具进行排序。

如果您使用Linux和bash,则可以将上面的for行替换为:

shopt -s extglob
ls -v FILE-+([0-9]).png | while read file; do

这段代码设置了bash的extglob shell选项,然后使用ls -v(这是Linux依赖项)来显示文件的受限视图。在解析ls时,不要犯诸如*.png之类的错误,因为你不想花时间预测如果文件名中有换行符会发生什么。如果你正在使用FreeBSD或OSX,或者没有使用bash,则需要采取额外措施,因为Almquish shell中没有extglobls -v
ls -f FILE-*.png | egrep '^FILE-[0-9]+\.png$' | sort -t- -k2n | while read file; do
  if [ ! -f "$file" ]; then
    continue
  fi

这可以分解如下:
  • ls -f在目录上不进行任何排序。文件规范限制了视图。
  • grep用于强制执行文件名格式,因为此模式无法完全表示为shell扩展。
  • sort -t- -k2n使用连字符分隔字段,然后在第二个字段上按数字进行排序。
  • 循环内部的if确保我们没有被某人搞砸,例如创建像FILE-1.png\nFILE-2.png这样的文件名。

1
谢谢您的帮助,但是它似乎没有按照预期工作。在第10行中,我实际上交换了“$n”和“$fn”的顺序,但得到了这个:`output.0001.testing4d.pngoutput.0001.testing4d.png`请注意,脚本保存为testing.sh,因此它以某种方式将脚本名称合并到重命名中。 - VanCityGuy
另一件事是它没有保持它们的顺序:output.0001.testing4d.pngoutput.0001.testing4d.png output.0005.testing4d.pngoutput.0007.testing4d.png output.0014.testing4d.pngoutput.0002.testing4d.png output.0099.testing4d.pngoutput.0008.testing4d.png output.0167.testing4d.pngoutput.0003.testing4d.png output.0199.testing4d.pngoutput.0004.testing4d.png output.0278.testing4d.pngoutput.0005.testing4d.png output.0455.testing4d.pngoutput.0006.testing4d.png - VanCityGuy
1
脚本顶部的fmt=行有一个拼写错误,现在已经被我修复了;第二个%被替换为$。几天没找到我的眼镜了,对混淆感到抱歉。不确定关于这是连续的发生了什么; for 行中的路径名扩展 *.png 应该按字母/数字顺序匹配文件。使用修复后的fmt行再次尝试并查看结果是否符合您的预期。 - ghoti
谢谢,这给了我我想要的正确输出。但仍然似乎按照原始未填充顺序输出它们。有没有一种方法可以先填充原始数字,然后在单独的命令中按顺序编号?我认为如果它执行两个单独的命令,它将正确排序。这个说法有道理吗? - VanCityGuy
1
添加了一些排序选项。不知道您正在运行哪个操作系统,因此我包含了一些可移植的选项。 - ghoti
谢谢。我在MacOSX中使用bash 4,但希望脚本在Linux中也能运行。你在更新中发布的第二个选项对我的需求很有效。非常感谢你的帮助! - VanCityGuy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接