如果存在某些匹配项,如何使用重新启动的序列重命名文件
How to rename file with a sequence that restarts if certain matches exist
这个标题并没有解释太多,但我无法快速总结。假设我有这样的文件(都在同一个目录中)...
abc_foo_file1_morestuff.ext
abc_foo_file2_morestuff.ext
efg_goo_file1_morestuff.ext
jkl_zoo_file0_morestuff.ext
jkl_zoo_file1_morestuff.ext
jkl_zoo_file4_morestuff.ext
xyz_roo_file6_morestuff.ext
我希望它们重命名为:
abc-1.ext
abc-2.ext
efg-1.ext
jkl-1.ext
jkl-2.ext
jkl-3.ext
xyz-1.ext
基本上,集合(abc、jkl、xyz)中的一些文件被删除,一些文件被重命名为其中有一个零,这样它们就会被列在第一位。但我想对它们重新排序以从 1 开始并且序列中没有任何间隙。
我用 Python 标记了它,因为这是我之前尝试过的,但如果有更简单或更清晰的方法,我完全赞成!
您可以使用批处理文件执行此操作:
@ECHO OFF
SETLOCAL EnableExtensions EnableDelayedExpansion
REM Process each EXT file in the specified directory.
FOR /F "usebackq tokens=* delims=" %%A IN (`DIR /B /S "C:\Path\To\Files\*.ext"`) DO (
REM Extract the prefix.
FOR /F "usebackq tokens=1 delims=_" %%X IN ('%%~nA') DO SET Prefix=%%X
REM Running tally of each prefix.
SET /A Count[!Prefix!] += 1
REM Rename the file using the prefix.
CALL SET NewName=!Prefix!-%%Count[!Prefix!]%%
REN "%%A" "!NewName!%%~xA"
)
ENDLOCAL
我解决这个问题的一般方法是以下步骤:
- 获取您要重命名的所有文件的列表
- 创建起始序列列表
- 浏览以每个序列更改名称开头的文件列表
- 可选地,对每个序列中的文件列表进行排序
所以,在 python 中看起来像:
from os import listdir
from os.path import isfile, join, splitext
import shutil
import re
mypath = "./somewhere/"
# this function taken from an answer to
def natural_sort_key(s, _nsre=re.compile('([0-9]+)')):
return [int(text) if text.isdigit() else text.lower()
for text in re.split(_nsre, s)]
# Get a list of all files in a directory
infiles = [f for f in listdir(mypath) if isfile(join(mypath, f))]
# Create a set of starting sequences
sequences = {splitext(file)[0].split('_')[0] for file in infiles}
# Now go about changing the files
for seq in sequences:
files = sorted([f for f in infiles if f.startswith(seq)],
key=natural_sort_key) # sort the files, if you like
for idx, file in enumerate(files):
new_name = seq + '-' + str(idx + 1) + '.' + splitext(file)[1][1:]
print(file, " -> ", new_name)
# copy or move
#shutil.copy2(join(mypath,file), join(mypath,new_name))
#shutil.move(join(mypath,file), join(mypath,new_name))
这是一个纯粹的 batch-file 解决方案,它满足您的所有要求(另请参阅 rem
评论):
@echo off
setlocal EnableExtensions
rem definition of temporary file:
set "TEMPFILE=%TMP%\~AlphaNum.tmp"
rem first loop structure for listing the files with `dir`
rem and creating the temporary file for later sorting:
> "%TEMPFILE%" (
for /F "eol=| tokens=1,2,3,* delims=_" %%I in ('
dir /B /A:-D "*_*_file*_*.ext"
') do (
rem store different parts of the file name into variables:
setlocal DisableDelayedExpansion
set "LINI=%%~I" & rem this is the very first part (prefix)
set "LINL=%%~J" & rem this is the part left to `file*`
set "LINM=%%~K" & rem this is the part `file*` (`*` is numeric)
set "LINR=%%~L" & rem this is the part right to `file*`
setlocal EnableDelayedExpansion
rem extract the numeric part of `file*` and pad with leading `0`s;
rem so the index is now of fixed width (12 figures at most here):
set "LINN=000000000000!LINM:*file=!" & set "LINN=!LINN:~-12!"
rem write file name with replaced fixed-width index and without
rem word `file`, followed by `|`, followed by original file name,
rem to the temporary file (the `echo` is redirected `>`):
echo !LINI!_!LINL!_!LINN!_!LINR!^|!LINI!_!LINL!_!LINM!_!LINR!
endlocal
endlocal
)
)
rem second loop structure for reading the temporary file,
rem sorting its lines with `sort`, generating new indexes
rem (sorting the previously built fixed-width indexes as text
rem result in the same order as sorting them as numbers) and
rem building the new file names (original first part + new index):
set "PREV="
for /F "eol=| tokens=2 delims=|" %%I in ('
sort "%TEMPFILE%"
') do (
setlocal DisableDelayedExpansion
rem get the full original file name, and its extension:
set "FILE=%%~I"
set "FEXT=%%~xI"
rem this loop iterates once only and extracts the part before the first `_`:
for /F "eol=| tokens=1 delims=_" %%X in ("%%~I") do (
set "CURR=%%~X"
)
setlocal EnableDelayedExpansion
rem if the current prefix equals the previous one, increment the index;
rem otherwise, reset the index to `1`:
if /I "!CURR!"=="!PREV!" (
set /A SNUM+=1
) else (
set /A SNUM=1
)
rem remove `ECHO` from the following line to actually rename files:
ECHO ren "!FILE!" "!CURR!-!SNUM!!FEXT!"
rem this loop iterates once only and transports the values of
rem some variable values past the `setlocal`/`endlocal` barrier:
for /F "tokens=1,* delims=|" %%X in ("!SNUM!|"!CURR!"") do (
endlocal
endlocal
set "SNUM=%%X"
set "PREV=%%~Y"
)
)
rem remove `REM` from the following line to delete temporary file:
REM del "%TEMPFILE%"
endlocal
需要切换 EnableDelayedExpansion
和 DisableDelayedExpansion
以使脚本对可能出现在文件名中的任何特殊字符(如 %
、!
、 (
、)
、&
和 ^
。在命令提示符中键入 set /?
以查找有关延迟变量扩展的简要信息。
此方法依赖于以下假设:
- 文件匹配模式
*_*_file*_*.ext
;
- none 个文件名部分
*
本身包含 _
个字符;
file
字后的索引为12位以内的十进制数;
- 第一个和第二个
_
之间的部分在排序顺序上优先于单词 file
之后的索引;例如,假设有两个文件 abc_AAA_file8_*.ext
和 abc_BBB_file5_*.ext
,abc_AAA_file8_*.ext
将重命名为 abc-1.ext
,而 abc_BBB_file5_*.ext
将重命名为 abc-2.ext
,因为 AAA
在 BBB
之前;如果这 不是 所需的行为,请将第一个循环结构中的 echo
命令行换成这个:
echo !LINI!_!LINN!_!LINL!_!LINR!^|!LINI!_!LINL!_!LINM!_!LINR!
;
- 新生成的索引没有用前导零填充;
对于您问题中的示例文件,临时文件包含以下行:
abc_foo_000000000001_morestuff.ext|abc_foo_file1_morestuff.ext
abc_foo_000000000002_morestuff.ext|abc_foo_file2_morestuff.ext
efg_goo_000000000001_morestuff.ext|efg_goo_file1_morestuff.ext
jkl_zoo_000000000000_morestuff.ext|jkl_zoo_file0_morestuff.ext
jkl_zoo_000000000001_morestuff.ext|jkl_zoo_file1_morestuff.ext
jkl_zoo_000000000004_morestuff.ext|jkl_zoo_file4_morestuff.ext
xyz_roo_000000000006_morestuff.ext|xyz_roo_file6_morestuff.ext
这个标题并没有解释太多,但我无法快速总结。假设我有这样的文件(都在同一个目录中)...
abc_foo_file1_morestuff.ext
abc_foo_file2_morestuff.ext
efg_goo_file1_morestuff.ext
jkl_zoo_file0_morestuff.ext
jkl_zoo_file1_morestuff.ext
jkl_zoo_file4_morestuff.ext
xyz_roo_file6_morestuff.ext
我希望它们重命名为:
abc-1.ext
abc-2.ext
efg-1.ext
jkl-1.ext
jkl-2.ext
jkl-3.ext
xyz-1.ext
基本上,集合(abc、jkl、xyz)中的一些文件被删除,一些文件被重命名为其中有一个零,这样它们就会被列在第一位。但我想对它们重新排序以从 1 开始并且序列中没有任何间隙。
我用 Python 标记了它,因为这是我之前尝试过的,但如果有更简单或更清晰的方法,我完全赞成!
您可以使用批处理文件执行此操作:
@ECHO OFF
SETLOCAL EnableExtensions EnableDelayedExpansion
REM Process each EXT file in the specified directory.
FOR /F "usebackq tokens=* delims=" %%A IN (`DIR /B /S "C:\Path\To\Files\*.ext"`) DO (
REM Extract the prefix.
FOR /F "usebackq tokens=1 delims=_" %%X IN ('%%~nA') DO SET Prefix=%%X
REM Running tally of each prefix.
SET /A Count[!Prefix!] += 1
REM Rename the file using the prefix.
CALL SET NewName=!Prefix!-%%Count[!Prefix!]%%
REN "%%A" "!NewName!%%~xA"
)
ENDLOCAL
我解决这个问题的一般方法是以下步骤:
- 获取您要重命名的所有文件的列表
- 创建起始序列列表
- 浏览以每个序列更改名称开头的文件列表
- 可选地,对每个序列中的文件列表进行排序
所以,在 python 中看起来像:
from os import listdir
from os.path import isfile, join, splitext
import shutil
import re
mypath = "./somewhere/"
# this function taken from an answer to
def natural_sort_key(s, _nsre=re.compile('([0-9]+)')):
return [int(text) if text.isdigit() else text.lower()
for text in re.split(_nsre, s)]
# Get a list of all files in a directory
infiles = [f for f in listdir(mypath) if isfile(join(mypath, f))]
# Create a set of starting sequences
sequences = {splitext(file)[0].split('_')[0] for file in infiles}
# Now go about changing the files
for seq in sequences:
files = sorted([f for f in infiles if f.startswith(seq)],
key=natural_sort_key) # sort the files, if you like
for idx, file in enumerate(files):
new_name = seq + '-' + str(idx + 1) + '.' + splitext(file)[1][1:]
print(file, " -> ", new_name)
# copy or move
#shutil.copy2(join(mypath,file), join(mypath,new_name))
#shutil.move(join(mypath,file), join(mypath,new_name))
这是一个纯粹的 batch-file 解决方案,它满足您的所有要求(另请参阅 rem
评论):
@echo off
setlocal EnableExtensions
rem definition of temporary file:
set "TEMPFILE=%TMP%\~AlphaNum.tmp"
rem first loop structure for listing the files with `dir`
rem and creating the temporary file for later sorting:
> "%TEMPFILE%" (
for /F "eol=| tokens=1,2,3,* delims=_" %%I in ('
dir /B /A:-D "*_*_file*_*.ext"
') do (
rem store different parts of the file name into variables:
setlocal DisableDelayedExpansion
set "LINI=%%~I" & rem this is the very first part (prefix)
set "LINL=%%~J" & rem this is the part left to `file*`
set "LINM=%%~K" & rem this is the part `file*` (`*` is numeric)
set "LINR=%%~L" & rem this is the part right to `file*`
setlocal EnableDelayedExpansion
rem extract the numeric part of `file*` and pad with leading `0`s;
rem so the index is now of fixed width (12 figures at most here):
set "LINN=000000000000!LINM:*file=!" & set "LINN=!LINN:~-12!"
rem write file name with replaced fixed-width index and without
rem word `file`, followed by `|`, followed by original file name,
rem to the temporary file (the `echo` is redirected `>`):
echo !LINI!_!LINL!_!LINN!_!LINR!^|!LINI!_!LINL!_!LINM!_!LINR!
endlocal
endlocal
)
)
rem second loop structure for reading the temporary file,
rem sorting its lines with `sort`, generating new indexes
rem (sorting the previously built fixed-width indexes as text
rem result in the same order as sorting them as numbers) and
rem building the new file names (original first part + new index):
set "PREV="
for /F "eol=| tokens=2 delims=|" %%I in ('
sort "%TEMPFILE%"
') do (
setlocal DisableDelayedExpansion
rem get the full original file name, and its extension:
set "FILE=%%~I"
set "FEXT=%%~xI"
rem this loop iterates once only and extracts the part before the first `_`:
for /F "eol=| tokens=1 delims=_" %%X in ("%%~I") do (
set "CURR=%%~X"
)
setlocal EnableDelayedExpansion
rem if the current prefix equals the previous one, increment the index;
rem otherwise, reset the index to `1`:
if /I "!CURR!"=="!PREV!" (
set /A SNUM+=1
) else (
set /A SNUM=1
)
rem remove `ECHO` from the following line to actually rename files:
ECHO ren "!FILE!" "!CURR!-!SNUM!!FEXT!"
rem this loop iterates once only and transports the values of
rem some variable values past the `setlocal`/`endlocal` barrier:
for /F "tokens=1,* delims=|" %%X in ("!SNUM!|"!CURR!"") do (
endlocal
endlocal
set "SNUM=%%X"
set "PREV=%%~Y"
)
)
rem remove `REM` from the following line to delete temporary file:
REM del "%TEMPFILE%"
endlocal
需要切换 EnableDelayedExpansion
和 DisableDelayedExpansion
以使脚本对可能出现在文件名中的任何特殊字符(如 %
、!
、 (
、)
、&
和 ^
。在命令提示符中键入 set /?
以查找有关延迟变量扩展的简要信息。
此方法依赖于以下假设:
- 文件匹配模式
*_*_file*_*.ext
; - none 个文件名部分
*
本身包含_
个字符; file
字后的索引为12位以内的十进制数;- 第一个和第二个
_
之间的部分在排序顺序上优先于单词file
之后的索引;例如,假设有两个文件abc_AAA_file8_*.ext
和abc_BBB_file5_*.ext
,abc_AAA_file8_*.ext
将重命名为abc-1.ext
,而abc_BBB_file5_*.ext
将重命名为abc-2.ext
,因为AAA
在BBB
之前;如果这 不是 所需的行为,请将第一个循环结构中的echo
命令行换成这个:echo !LINI!_!LINN!_!LINL!_!LINR!^|!LINI!_!LINL!_!LINM!_!LINR!
; - 新生成的索引没有用前导零填充;
对于您问题中的示例文件,临时文件包含以下行:
abc_foo_000000000001_morestuff.ext|abc_foo_file1_morestuff.ext abc_foo_000000000002_morestuff.ext|abc_foo_file2_morestuff.ext efg_goo_000000000001_morestuff.ext|efg_goo_file1_morestuff.ext jkl_zoo_000000000000_morestuff.ext|jkl_zoo_file0_morestuff.ext jkl_zoo_000000000001_morestuff.ext|jkl_zoo_file1_morestuff.ext jkl_zoo_000000000004_morestuff.ext|jkl_zoo_file4_morestuff.ext xyz_roo_000000000006_morestuff.ext|xyz_roo_file6_morestuff.ext