我现在删除了所有内容。为了证明其余代码实际上不是问题的原因,我创建了以下内容dummy.bat
:
@ECHO OFF & cls
SETLOCAL EnableDelayedExpansion
ECHO THIS IS EXAMPLE 1 (Not working as expected - look at the end)
ECHO.
set "OutLoc=K:\Tools\Video Tools\ffmpeg-4.3.1-win64-static\output\Amorphis - Discographie 1992-2013\2010 - Magic & Mayhem (320)\2010 - Magic & Mayhem (320)\12 - My Kantele.mp3"
set "FileName=12 - My Kantele.mp3"
set "ShortFileName=12 - My Kantele"
ECHO FileName: !FileName!
ECHO ShortFileName: !ShortFileName!
set OutDir=!OutLoc!
call set OutDir=%%OutDir:!FileName!=%%
call set OutLoc=%%OutLoc:!FileName!=%%!!ShortFileName!.mp3
ECHO OutDir: !OutDir!
ECHO OutLoc: !OutLoc!
ECHO.
ECHO.
ECHO THIS IS EXAMPLE 2 (Working as expected)
ECHO.
set "OutLoc=K:\Tools\Video Tools\ffmpeg-4.3.1-win64-static\output\Amorphis - Discographie 1992-2013\2010 - Forging The Land Of Thousand Lakes (320)\2010 - Forging The Land Of Thousand Lakes (320)\CD1\08 - Silent Waters.mp3"
set "FileName=08 - Silent Waters.mp3"
set "ShortFileName=08 - Silent Waters"
ECHO FileName: !FileName!
ECHO ShortFileName: !ShortFileName!
set OutDir=!OutLoc!
call set OutDir=%%OutDir:!FileName!=%%
call set OutLoc=%%OutLoc:!FileName!=%%!!ShortFileName!.mp3
ECHO OutDir: !OutDir!
ECHO OutLoc: !OutLoc!
现在让我们看看,纯字符串是否可以复制我想要解决的问题。让我们看看示例 1 和示例 2 的输出,看看有什么不同:
- 这是示例 1 // 未按预期工作 - 请查看结尾
FileName: 12 - My Kantele.mp3
ShortFileName: 12 - My Kantele
OutDir: K:\Tools\Video Tools\ffmpeg-4.3.1-win64-static\output\Amorphis - Discographie 1992-2013\2010 - Magic & Mayhem (320)\2010 - Magic & Mayhem (320)\12 - My Kantele.mp3
OutLoc: K:\Tools\Video Tools\ffmpeg-4.3.1-win64-static\output\Amorphis - Discographie 1992-2013\2010 - Magic & Mayhem (320)\2010 - Magic & Mayhem (320)\12 - My Kantele.mp3
- 这是示例 2 // 按预期工作
FileName: 08 - Silent Waters.mp3
ShortFileName: 08 - Silent Waters
OutDir: K:\Tools\Video Tools\ffmpeg-4.3.1-win64-static\output\Amorphis - Discographie 1992-2013\2010 - Forging The Land Of Thousand Lakes (320)\2010 - Forging The Land Of Thousand Lakes (320)\CD1\
OutLoc: K:\Tools\Video Tools\ffmpeg-4.3.1-win64-static\output\Amorphis - Discographie 1992-2013\2010 - Forging The Land Of Thousand Lakes (320)\2010 - Forging The Land Of Thousand Lakes (320)\CD1\08 - Silent Waters.mp3
所以很明显,其余代码 - 正如我所说的 - 是不相关的。
这两个示例都使用了我之前测试的原始路径。那么怎么会有所不同呢?两者都只是带有空格和一些括号的字符串……有什么想法吗?字符串替换有长度限制吗?
答案1
在之前的版本中我看到当前发布的这部分代码来自循环for
,所以......
我认为你可以通过做一些改变来获得更好的结果set "variables=substring"
...
for %%F in ("!FileLoc!")do (
set FileName=%%~nxF
set ShortFileName=%%~nF
ECHO FileName NXF: %%~nxF
ECHO ShortFileName nF %%~nF
)
set OutDir=!OutLoc!
call set OutDir=%%OutDir:!FileName!=%%
call set OutLoc=%%OutLoc:!FileName!=%%!!ShortFileName!.mp3
ECHO OutDir: !OutDir!
ECHO OutLoc: !OutLoc!
- 删除此循环并使用来自第一个/上一个循环的变量扩展
for
来定义子字符串,我没有看到需要使用子字符串和另一个变量来定义变量...
set "FileName=%%~nxa"
set "ShortFileName=%%~na"
echo\FileName NXA: "%%~nxa"
echo\ShortFileName nA: "%%~na"
set "OutDir=!OutLoc!"
set "OutDir=!OutDir:%%~nxa=!"
set "OutLoc=!OutLoc:%%~xa=!.mp3"
echo\OutDir: "!_OutDir!"
echo\OutLoc: "!_OutLoc!"
- 定义/使用变量时请记住“双引号”,这样可以避免文件夹/文件名中出现任何特殊字符的问题......
观察:使用if
整数 [ EQU, NEQ, LSS, LEQ, GTR, GEQ
] 整数(
..
我会添加一些建议,但请理解,我不知道你的内容和/或布局%@RootPath%Aformats.cfg
文件。
@echo off && cls
setlocal EnableDelayedExpansion
rem :: define 2 variable integers in one command/line ::
set /a "_LogEnabled=1, _ResetLog=1"
rem :: you can remove () from else (command) ::
if !_LogEnabled! equ 1 (echo\Logging is enabled) ELSE echo\Logging is disabled...
rem :: concatenated rem./ and command in same line ::
rem./ :: defining output path && set "_OutPath=%~dp0output\"
rem./ :: defining input path && set "_InPath=%~dp0tinput\"
rem./ :: defining batch path && set "_RootPath=%~dp0"
rem./ :: defining batch drive && set "_InDrive=%~d0\"
cd /D "!_InPath!"
rem :: 2>nul ommit any possible warnning/error ::
if !_ResetLog! equ 1 2>nul del/F /Q "!_RootPath!log.txt"
rem :: the label :_timestamp will use one fixed date/time output layout ::
rem :: to define the same timestamp leading by 0 and using the safe way ::
rem :: to get current day month and year in batch (see linked question) ::
call :_timestamp
if !_LogEnabled! equ 1 echo :: !_dtstamp! :: Starting conversion >>"!_RootPath!log.txt"
rem :: read all listed audio files ::
for /F tokens^=*^usebackq %%Z in ("!_RootPath!aformats.cfg")do for /r %%a in ("*.%%~Z")do (
set "_FileLoc=%%~dpa%%~nxa"
set "_FileLocRel=%%~dpa%%~nxa"
set "_FileLocRel=!_FileLocRel:%~dp0tinput\=!"
set "_OutLocRel=%%~dpa%%~nxa"
set "_OutLocRel=!_OutLocRel:%~dp0tinput\=!"
set "_OutLoc=!_RootPath!output\!_OutLocRel!"
echo\OUTLOCRELATIVE: "!_OutLocRel!"
echo\OUTLOC: "!_OutLoc!"
set "_FailedPath=!_RootPath!failed\!_OutLocRel!"
echo\This is the fileloc: "!_FileLoc!"
set "_FileName=%%~nxa"
set "_ShortFileName=%%~na"
echo\FileName NXA: "%%~nxa"
echo\ShortFileName nA: "%%~na"
set "_OutDir=!_OutLoc!"
set "_OutDir=!_OutDir:%%~nxa=!"
set "_OutLoc=!_OutLoc:%%~xa=!.mp3"
set "_FailedPath=!_FailedPath:%%~na=!"
echo\OutDir: "!_OutDir!"
echo\OutLoc: "!_OutLoc!"
echo\Now processing: "!_FileLocRel!"
rem :: updated date/time ::
call :_timestamp
if !_LogEnabled! equ 1 echo :: !_dtstamp! :: Now processing: !_FileLocRel!... >>"!_RootPath!log.txt"
rem :: Reading length value into a temp file for later access ::
!_RootPath!bin\ffprobe.exe" -i "!_FileLoc!" -show_entries format=duration -v quiet -of csv="p=0" >>"!_RootPath!length.temp"
rem :: These are required to calculate the output bitrate ::
"!_RootPath!bin\ffprobe.exe" -i "!_FileLoc!" -show_entries format=size -v quiet -of csv="p=0" >>"!_RootPath!size.temp"
rem :: Resetting length (in case of corrupted file) ::
rem :: also, define 2 integers in one command/line ::
set /a "_length=0, _size=0"
rem :: Reading length from file as a value
for /F "tokens=*" %%T in ('type "!_RootPath!length.temp"')do set "_length=%%T"
rem :: Reading size from file as a value
for /F "tokens=*" %%S in ('type "!_RootPath!size.temp"')do set "_size=%%S"
rem :: you can concatenate your variables to check the size using just an if ::
if !_size!!_length! leq 0 (
echo\!_FileLocRel! seems to be corrupted or invalid. Ignoring file...
set "_SeemsInvalid=1") ELSE set "_SeemsInvalid=0"
if !_LogEnabled! equ 1 (
rem :: updated date/time ::
call :_timestamp
echo\:: !_dtstamp! :: Error: !_FileLocRel! seems to be corrupted or invalid. Ignoring file... >>"!_RootPath!log.txt"
)
rem :: create your folder and if exist, just ommit any possible warnning/error ::
2>nul mkdir "!_FailedPath!"
rem :: Save to ...\failed\ and mute response in CMD ::
>nul xcopy /s /z /y "!_FileLoc!" "!_FailedPath!"
rem :: Check if output subdirectories exist, if not, create them ::
if EXIST "!_OutDir!\." (
echo\DIRECTORY "!_OutDir!" EXISTS - it seems to be at least
echo\AND This is the outloc: "!_outloc!"
) ELSE mkdir "!_OutDir!"
if !_LogEnabled! equ 1 (
rem :: updated date/time ::
call :_timestamp
echo\:: !_dtstamp! :: Making new directory: MKDIR "!_OutDir!" >>"!_RootPath!log.txt"
)
rem :: replacing [if exist (echo\nothing>>nul..) else do...] to single action ::
if not EXIST "!_OutLoc!" if !_SeemsInvalid! equ 0 (
rem :: define 2 integers in one command/line ::
set /A "_InBitrate=!_size!*1, _InBitrate=!_InBitrate!/!_length!"
)
if !_InBitrate! gtr 320000 (
echo\Target bitrate exceeds 320kbit/s
set "_InBitrate=320000"
)
echo\Target bitrate: !_InBitrate!
if !_LogEnabled! equ 1 (
rem :: updated date/time ::
call :_timestamp
echo\:: !_dtstamp! ::
"!_RootPath!bin\ffmpeg.exe" -n -i "!_FileLoc!" -codec:a libmp3lame -b:a !_InBitrate! "!_OutLoc!" >>"!_RootPath!log.txt"
)
"!_RootPath!bin\ffmpeg.exe" -n -i "!_FileLoc!" -codec:a libmp3lame -b:a !_InBitrate! "!_OutLoc!"
rem :: Cleaning up temp files for next loop (deleting 2 files in one command) ::
2>nul del/F /Q "!_RootPath!length.temp" "!_RootPath!size.temp"
)
)
if !_LogEnabled! equ 1 (
rem :: updated date/time ::
call :_timestamp
echo :: !_dtstamp! :: Conversion finished >>"!_RootPath!log.txt"
)
endlocal & goto :EOF
:_timestamp < :: Tue 25:08:2020 - 23:36:48.52 :: >
rem :: Define a pseudo array for the day of the week, which will be ::
rem :: used in the third for loop to literal define day of the week ::
set "_wday=0-Sun,1-Mon,2-Tue,3-Wed,4-Thu,5-Fri,6-Sat"
rem :: get day, day of the week, month, year and time (hour), and ::
rem :: regardless of location or regardless of any user settings ::
for /f %%i in ('^^^< nul %__APPDIR__%wbem\wmic.exe os get LocalDateTime^|find "."')do (
set "_dt=%%i"
set "_dt=!_dt:~6,2!:!_dt:~4,2!:!_dt:~0,4! - !_dt:~8,2!:!time:~3!"
)
rem :: Take the day of the week and use a second for loop to check which of elements of %%D in ::
rem :: pseudo array corresponds, when it occur (%%D equ %%i), will set "_day_of_the_week=%%~E" ::
rem :: if %%D equ 2 set "day_of_the_week=B", if 2 equ 2 set "_wd=%%~E", and timestamp will set ::
for /f %%i in ('^^^< nul %__APPDIR__%wbem\wmic.exe Path Win32_LocalTime Get DayOfWeek')do (
for %%L in (!_wday!)do for /f tokens^=1-2^delims^=- %%D in ('echo\%%~L')do if %%D equ %%i (
set "_wd=%%~E"
set "_dtstamp=!_wd!!_dt!"
exit /b
)
)
答案2
那么怎么会有所不同呢?两者都只是带有空格和一些括号的字符串...有什么想法吗?
示例脚本中的问题似乎是路径&
中的文字符号OutLoc
。&
是特殊字符在 Windows 的命令行中,似乎导致了意外行为。使用插入&
符号转义这两个符号^
(因此它们被解释为常规字符)会产生所需的输出:
例如&
用^&
( short-dummy.bat
)替换
@ECHO OFF & cls
SETLOCAL EnableDelayedExpansion
@REM [...]
set "OutLoc=K:\Tools\Video Tools\ffmpeg-4.3.1-win64-static\output\Amorphis - Discographie 1992-2013\2010 - Magic ^& Mayhem (320)\2010 - Magic ^& Mayhem (320)\12 - My Kantele.mp3"
set "FileName=12 - My Kantele.mp3"
set "ShortFileName=12 - My Kantele"
ECHO FileName: !FileName!
ECHO ShortFileName: !ShortFileName!
set OutDir=!OutLoc!
call set OutDir=%%OutDir:!FileName!=%%
call set OutLoc=%%OutLoc:!FileName!=%%!!ShortFileName!.mp3
ECHO OutDir: !OutDir!
ECHO OutLoc: !OutLoc!
@REM [...]
例如替换&
为^&
(short-dummy.bat
输出)
FileName: 12 - My Kantele.mp3
ShortFileName: 12 - My Kantele
OutDir: K:\Tools\Video Tools\ffmpeg-4.3.1-win64-static\output\Amorphis - Discographie 1992-2013\2010 - Magic & Mayhem (320)\2010 - Magic & Mayhem (320)\
OutLoc: K:\Tools\Video Tools\ffmpeg-4.3.1-win64-static\output\Amorphis - Discographie 1992-2013\2010 - Magic & Mayhem (320)\2010 - Magic & Mayhem (320)\12 - My Kantele.mp3