在 windows 批次中从文件名字符串中获取一个变量
Get a variable from filename string in windows batch
美好的一天,我有一个包含 400 个文件的文件夹,我想从文件名中打印一个“名称”
这是结构
ej:
20201323223_vendo.perfil01_17872513294967257_1601950878_live.mp4
20201323223__vvcastrillon_12_17949951031375250_1601939874_live.mp4
2020323123_yessromero.g_17849208194340047_1601945592_live.mp4
2020323223_ziizii_08_17979840166310477_1601929868_live.mp4
而我需要的是
vendo.perfil01
_vvcastrillon_12
yessromero.g
ziizii_08
我尝试在文件中循环并用 _ 分开并提取 2 和 3 标记数字条件,但结果是错误的并且缺少变量
@echo off
setlocal EnableDelayedExpansion
:loop
SET max=5000
for /F "delims=" %%I in ('dir "*_*_*.mp4" /A-D /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V "\outdir\"') do (for /F "eol=| tokens=2,3 delims=_" %%J in ("%%~nI") do (SET "var="&for /f "delims=0123456789" %%a in ("%%K") do SET var=%%a
if defined var ( set nam=%%J_%%K ) else ( set nam=%%J )
)
echo/!nam!
)
timeout 10 > nul
goto loop
我认为答案是删除 _ 之前的第一个数字,然后删除最后的字符串 _xxxxxx_xxxxxxx_live.mp4 但我不知道如何反向读取标记
感谢任何帮助
这样的事情应该有所帮助:
@echo off
setlocal enabledelayedexpansion
for /f "tokens=1* delims=_." %%i in ('dir /b /s /a-d "*_*_*.mp4"2^>nul ^| findstr.exe /ILV "\outdir\"') do (
set "var=%%j"
for /f "tokens=2,* delims=_." %%a in ("%%j") do echo !var:_%%b=!
)
请记住,使用 delims
也会拆分连续的字符,例如双下划线。对于那些你需要预先确定哪个有双下划线并让脚本为你添加它的人。
由于您的文件名中有不同数量的 _
分隔项,甚至相邻 _
,因此使用 for /F
将它们拆分为具有 [=16] 的特定标记=] 不是最好的选择。
我会使用标准 for
-loop,它接收修改后的文件名,即每个 _
替换为 " "
并包含在 ""
中,这导致SPACE-分隔的部分名称项。所以:
20201323223_vendo.perfil01_17872513294967257_1601950878_live.mp4
更改为:
"20201323223" "vendo.perfil01" "17872513294967257" "1601950878" "live.mp4"
循环之前。在循环中实现一个索引计数器,并将这些项目附加到一个缓冲区,该缓冲区的索引号位于特定范围内,该范围取决于项目总数。
这是一个演示我的意思的示例脚本:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=%~dp0." & rem // (full path to target directory)
set "_MASK=*_*_*_*_live.mp4" & rem // (pattern to match file names)
set "_FILT=^[0123456789][0123456789]*_..*_[0123456789][0123456789]*_[0123456789][0123456789]*_live\.mp4$"
rem // (additional `findstr` filter for file names)
set /A "_POS=1" & rem /* (index of first `_`-separated item to extract;
rem `0` is the first item, `-1` is the last) */
set /A "_NUM=-4" & rem /* (number of `_`-separated items to extract;
rem `-1` means all up to the last item) */
rem // Change into target directory:
pushd "%_ROOT%" && (
rem // Loop through all matching non-hidden, non-system files:
for /F "delims= eol=|" %%F in ('
dir /B /A:-D-H-S "%_MASK%" ^| findstr /I /R /C:"%_FILT%"
') do (
rem // Store current file name, initialise item index, counter and buffer:
set "FILE=%%F" & set /A "IDX=-1, CNT=-1" & set "BUFF=_"
rem // Toggle delayed expansion to avoid troubles with `!`:
setlocal EnableDelayedExpansion
rem // Count number of items and store one less:
rem set "TEST=%FILE:_=" & set /A "CNT+=1" & set "TEST=%"
for %%I in ("!FILE:_=" "!") do set /A "CNT+=1"
rem // Determine item index position from given index and number:
if !_POS! lss 0 (set /A "BEG=CNT+_POS+1") else set /A "BEG=_POS"
if !_NUM! lss 0 (set /A "END=CNT+_NUM+1") else set /A "END=_POS+_NUM-1"
rem // Transport numbers over `endlocal` barrier:
for %%C in (!CNT!) do for %%B in (!BEG!) do for %%A in (!END!) do (
rem // Loop through `_`-separated items of file name:
for %%I in ("!FILE:_=" "!") do (
rem // Store current item, increment item index:
endlocal & set "ITEM=%%~I" & set /A "IDX+=1"
setlocal EnableDelayedExpansion
rem // Append current item to buffer if in range:
if !IDX! geq %%B if !IDX! leq %%A (
rem // Transport buffer over `endlocal` barrier:
for /F "delims=" %%E in ("BUFF=!BUFF!_!ITEM!") do (
endlocal & set "%%E"
setlocal EnableDelayedExpansion
)
)
)
)
rem // Return buffer:
echo(!BUFF:~2!
endlocal
)
rem // Return from target directory:
popd
)
endlocal
exit /B
@ECHO OFF
SETLOCAL
for %%a in (
20201323223_vendo.perfil01_17872513294967257_1601950878_live.mp4
20201323223__vvcastrillon_12_17949951031375250_1601939874_live.mp4
2020323123_yessromero.g_17849208194340047_1601945592_live.mp4
2020323223_ziizii_08_17979840166310477_1601929868_live.mp4
) do set "filename=%%a" &call :process&echo --------------------------------------
GOTO :EOF
:process
echo stage 1 %filename%
:: step 1 : delete all characters up to and including the first underscore
set "filename=%filename:*_=%"
echo stage 2 %filename%
:: step 2 : find all numeric strings of length 4 or more in remainder
call :strsgt4 %filename:_= %
:: step 3 : replace each numeric string of length 4 or more + preceding underscore with "/" (invalid filename character)
echo stage 3 %filename%
:proc3lp
if "%zapstrings%" neq " " for %%v in (%zapstrings%) do call set "filename=%%filename:_%%v=/%%"&call set "zapstrings=%%zapstrings: %%v=%%"&goto proc3lp
echo stage 4 %filename%
:: step 5 : Remove all charactersincluding and after the first "/"
for /f "delims=/" %%v in ("%filename%") do echo result %%v
goto :eof
:strsgt4
set "zapstrings= "
:strsgt4loop
set "test=%1"
if not defined test goto :eof
set "test=%test:~4%"
if defined test call :isnum %test%&if not defined notnumber set "zapstrings=%zapstrings% %1"
shift
goto strsgt4loop
:: Determine whether %1 is purely numeric
:isnum
SET "notnumber=9%~1"
FOR /l %%z IN (0,1,9) DO CALL SET "notnumber=%%notnumber:%%z=%%"
GOTO :eof
真正的问题是制定你的规则。
我决定你的规则是:第一个下划线之后的字符串,直到数字字符串或长度大于 3 的第一个后续下划线之前
%%a
循环简单地向 :process
提交一系列示例字符串
行内注释应解释其余部分。
美好的一天,我有一个包含 400 个文件的文件夹,我想从文件名中打印一个“名称” 这是结构 ej:
20201323223_vendo.perfil01_17872513294967257_1601950878_live.mp4
20201323223__vvcastrillon_12_17949951031375250_1601939874_live.mp4
2020323123_yessromero.g_17849208194340047_1601945592_live.mp4
2020323223_ziizii_08_17979840166310477_1601929868_live.mp4
而我需要的是
vendo.perfil01
_vvcastrillon_12
yessromero.g
ziizii_08
我尝试在文件中循环并用 _ 分开并提取 2 和 3 标记数字条件,但结果是错误的并且缺少变量
@echo off
setlocal EnableDelayedExpansion
:loop
SET max=5000
for /F "delims=" %%I in ('dir "*_*_*.mp4" /A-D /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V "\outdir\"') do (for /F "eol=| tokens=2,3 delims=_" %%J in ("%%~nI") do (SET "var="&for /f "delims=0123456789" %%a in ("%%K") do SET var=%%a
if defined var ( set nam=%%J_%%K ) else ( set nam=%%J )
)
echo/!nam!
)
timeout 10 > nul
goto loop
我认为答案是删除 _ 之前的第一个数字,然后删除最后的字符串 _xxxxxx_xxxxxxx_live.mp4 但我不知道如何反向读取标记
感谢任何帮助
这样的事情应该有所帮助:
@echo off
setlocal enabledelayedexpansion
for /f "tokens=1* delims=_." %%i in ('dir /b /s /a-d "*_*_*.mp4"2^>nul ^| findstr.exe /ILV "\outdir\"') do (
set "var=%%j"
for /f "tokens=2,* delims=_." %%a in ("%%j") do echo !var:_%%b=!
)
请记住,使用 delims
也会拆分连续的字符,例如双下划线。对于那些你需要预先确定哪个有双下划线并让脚本为你添加它的人。
由于您的文件名中有不同数量的 _
分隔项,甚至相邻 _
,因此使用 for /F
将它们拆分为具有 [=16] 的特定标记=] 不是最好的选择。
我会使用标准 for
-loop,它接收修改后的文件名,即每个 _
替换为 " "
并包含在 ""
中,这导致SPACE-分隔的部分名称项。所以:
20201323223_vendo.perfil01_17872513294967257_1601950878_live.mp4
更改为:
"20201323223" "vendo.perfil01" "17872513294967257" "1601950878" "live.mp4"
循环之前。在循环中实现一个索引计数器,并将这些项目附加到一个缓冲区,该缓冲区的索引号位于特定范围内,该范围取决于项目总数。
这是一个演示我的意思的示例脚本:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=%~dp0." & rem // (full path to target directory)
set "_MASK=*_*_*_*_live.mp4" & rem // (pattern to match file names)
set "_FILT=^[0123456789][0123456789]*_..*_[0123456789][0123456789]*_[0123456789][0123456789]*_live\.mp4$"
rem // (additional `findstr` filter for file names)
set /A "_POS=1" & rem /* (index of first `_`-separated item to extract;
rem `0` is the first item, `-1` is the last) */
set /A "_NUM=-4" & rem /* (number of `_`-separated items to extract;
rem `-1` means all up to the last item) */
rem // Change into target directory:
pushd "%_ROOT%" && (
rem // Loop through all matching non-hidden, non-system files:
for /F "delims= eol=|" %%F in ('
dir /B /A:-D-H-S "%_MASK%" ^| findstr /I /R /C:"%_FILT%"
') do (
rem // Store current file name, initialise item index, counter and buffer:
set "FILE=%%F" & set /A "IDX=-1, CNT=-1" & set "BUFF=_"
rem // Toggle delayed expansion to avoid troubles with `!`:
setlocal EnableDelayedExpansion
rem // Count number of items and store one less:
rem set "TEST=%FILE:_=" & set /A "CNT+=1" & set "TEST=%"
for %%I in ("!FILE:_=" "!") do set /A "CNT+=1"
rem // Determine item index position from given index and number:
if !_POS! lss 0 (set /A "BEG=CNT+_POS+1") else set /A "BEG=_POS"
if !_NUM! lss 0 (set /A "END=CNT+_NUM+1") else set /A "END=_POS+_NUM-1"
rem // Transport numbers over `endlocal` barrier:
for %%C in (!CNT!) do for %%B in (!BEG!) do for %%A in (!END!) do (
rem // Loop through `_`-separated items of file name:
for %%I in ("!FILE:_=" "!") do (
rem // Store current item, increment item index:
endlocal & set "ITEM=%%~I" & set /A "IDX+=1"
setlocal EnableDelayedExpansion
rem // Append current item to buffer if in range:
if !IDX! geq %%B if !IDX! leq %%A (
rem // Transport buffer over `endlocal` barrier:
for /F "delims=" %%E in ("BUFF=!BUFF!_!ITEM!") do (
endlocal & set "%%E"
setlocal EnableDelayedExpansion
)
)
)
)
rem // Return buffer:
echo(!BUFF:~2!
endlocal
)
rem // Return from target directory:
popd
)
endlocal
exit /B
@ECHO OFF
SETLOCAL
for %%a in (
20201323223_vendo.perfil01_17872513294967257_1601950878_live.mp4
20201323223__vvcastrillon_12_17949951031375250_1601939874_live.mp4
2020323123_yessromero.g_17849208194340047_1601945592_live.mp4
2020323223_ziizii_08_17979840166310477_1601929868_live.mp4
) do set "filename=%%a" &call :process&echo --------------------------------------
GOTO :EOF
:process
echo stage 1 %filename%
:: step 1 : delete all characters up to and including the first underscore
set "filename=%filename:*_=%"
echo stage 2 %filename%
:: step 2 : find all numeric strings of length 4 or more in remainder
call :strsgt4 %filename:_= %
:: step 3 : replace each numeric string of length 4 or more + preceding underscore with "/" (invalid filename character)
echo stage 3 %filename%
:proc3lp
if "%zapstrings%" neq " " for %%v in (%zapstrings%) do call set "filename=%%filename:_%%v=/%%"&call set "zapstrings=%%zapstrings: %%v=%%"&goto proc3lp
echo stage 4 %filename%
:: step 5 : Remove all charactersincluding and after the first "/"
for /f "delims=/" %%v in ("%filename%") do echo result %%v
goto :eof
:strsgt4
set "zapstrings= "
:strsgt4loop
set "test=%1"
if not defined test goto :eof
set "test=%test:~4%"
if defined test call :isnum %test%&if not defined notnumber set "zapstrings=%zapstrings% %1"
shift
goto strsgt4loop
:: Determine whether %1 is purely numeric
:isnum
SET "notnumber=9%~1"
FOR /l %%z IN (0,1,9) DO CALL SET "notnumber=%%notnumber:%%z=%%"
GOTO :eof
真正的问题是制定你的规则。
我决定你的规则是:第一个下划线之后的字符串,直到数字字符串或长度大于 3 的第一个后续下划线之前
%%a
循环简单地向 :process
行内注释应解释其余部分。