CMD:提取文件名的一部分并将其用作变量

CMD: extract part of a filename and use it as variable

我用 EAC 将我的 CD 翻录成 CUE+WAV 文件,添加了封面,我的所有文件都在同一个文件夹中,文件名模式为 "Album artist - Album title",例如:

Clannad - Legend.wav/cue/jpg
David Bowie - Best Of Bowie [Disc 1].wav/cue/jpg
David Bowie - Best Of Bowie [Disc 2].wav/cue/jpg

我是新手所以我写了一个简单的 CMD 批处理来将我的音乐转换为 FLAC 格式,但是它需要手动复制和粘贴实际的 wav/cue/jpg 文件名和专辑艺术家的输入,光盘号.和总盘号为他们相应的标签。由于某些原因,它不能存储在 cuesheet 文件中,但就我而言,我将它们保存在文件名中,如您在上面所见)。

ECHO WAV/CUE/JPG FILENAME
SET /P "input="
ECHO ALBUMARTIST
SET /P "albumartist="
ECHO DISCNUMBER
SET /P "discnumber="
ECHO TOTALDISCS
SET /P "totaldiscs="

flac.exe -0 --picture="D:\Music\%input%.jpg" --tag-from-file="CUESHEET=D:\Music\%input%.cue" -T "ALBUMARTIST=%albumartist%" -T "DISCNUMBER=%discnumber%" -T "TOTALDISCS=%totaldiscs%" "D:\Music\%input%.wav"

我的问题是关于自动转换我所有翻录的专辑。如何提取专辑 artist/disc 编号/总光盘编号。来自文件名的信息并为每个 .wav 文件循环?

@ECHO OFF
SETLOCAL
SET "destdir=U:\destdir"
PUSHD "%destdir%"
:: Find all .jpgs where there is a .wav and .cue with the same name
FOR /f "delims=" %%a IN ('dir /b /a-d *.jpg') DO IF EXIST "%%~na.wav" IF EXIST "%%~na.cue" (
 FOR %%b IN (input albumartist discnumber totaldiscs) DO SET "%%b="
 SET "input=%%~na"
 FOR /f "delims=-" %%b IN ("%%a") DO SET "albumartist=%%b"
 FOR /f "tokens=2delims=[]" %%b IN ("%%a") DO SET "disc=%%b"
 IF DEFINED disc (
  FOR /f "tokens=1delims=[]" %%d IN ("%%a") DO FOR /f %%c IN ('dir /b "%%d[*.wav"') DO SET /a totaldiscs+=1
 )
 CALL :gflac
)

POPD

GOTO :EOF

:gflac
:: remove trailing spaces from INPUT
IF "%albumartist:~-1%"==" " SET "albumartist=%albumartist:~0,-1%"&GOTO gflac
:: presume default for disc and totaldiscs
IF DEFINED disc (FOR /f "tokens=2" %%d IN ("%disc%") DO SET /a disc=%%d) ELSE (SET /a disc=1)
IF NOT DEFINED totaldiscs SET /a totaldiscs=1
ECHO( flac.exe -0 --picture="D:\Music\%input%.jpg" --tag-from-file="CUESHEET=D:\Music\%input%.cue" -T "ALBUMARTIST=%albumartist%" -T "DISCNUMBER=%discnumber%" -T "TOTALDISCS=%totaldiscs%" "D:\Music\%input%.wav"
GOTO :eof

您需要更改 destdir 的设置以适合您的情况。

以上只是 echo 所需的 flac 行。我在你发布时留下了它,但在我的 U: 驱动器上设置了你发布的少量测试数据(即有一组 3 个文件)。

遗憾的是,您提供给我们的信息不足。我假设您需要所有三个文件都存在,totaldiscs 的默认值为 1。

首先寻找所有的.jpgs,如果有对应的.wav.cue则对flac的生成进行如下处理:

  • input 设置为找到的 .jpg 的名称部分
  • albumartist 设置为文件名的第一部分,直到 -
  • 获取 [disc n] 字符串(如果存在)
  • 计算文件名开头到 [
  • .wav 的数量
  • 生成 flac 行。

flac行的生成中,我们去掉input的尾随空格,将disc n转换为n或将disc设置为1(尽管这可能不需要信息),如果未计算,则将 totaldiscs 设置为 1。

你没有说 flac 产生了什么作为输出,但我建议你进一步控制该文件类型,这样如果 %input%.finalproductwhateverthatis文件存在。

[根据 dbenham 的评论编辑]

这与 Magoo 的回答非常相似,修复了一些错误,并且所有操作都在一个主循环中完成,无需调用。与 Magoo 的回答一样,在开头修改目标文件夹以满足您的需要。

@echo off
:: Delayed expansion must be disabled to protect ! when expanding FOR variables.
:: It is normally disabled by default, but I'm making it explicit, just to be sure.
setlocal disableDelayedExpansion

:: Define where source files are coming from
set "source=D:\Music"

:: Define where output should be stored
set "destination=D:\Music"

pushd "%destination%"

:: Iterate each .wav file (A) and only proceed if .jpg and .cue also exists
for /f "delims=" %%A in ('dir /b /a-d "%source%\*.wav"') do if exist "%source%\%%~nA.jpg" if exist "%source%\%%~nA.cue" (

  %= Get base name with path, but without extension =%
  set "file=%source%\%%~nA"

  %= Extract "artist - album " (B) and "Disc #" (C) from base name (~nA) =%
  for /f "delims=[] tokens=1,2" %%B in ("%%~nA") do (

    %= Extract "artst " (D) from "artist - abum ". (~nxD) trims trailing space =%
    for /f "delims=-" %%D in ("%%B") do set "artist=%%~nxD"

    %= Extract the number (E) from "Disc #", use 1 as default if not there =%
    set "disc=1"
    for /f "tokens=2" %%E in ("%%C") do set "disc=%%E"

    %= Count the number of discs (F), will be 0 if no [Disc #] =%
    %= The [ is appended to name to prevent something like "Greatest Hits 2" from matching "Greatist Hits" =%
    for /f %%F in ('dir /b /a-d "%source%\%%B[*.wav" 2^>nul ^|find /c /v ""') do set "count=%%F"

    %= temporarily enable delayed expansion to access variables set within loop =%
    setlocal enableDelayedExpansion

    %= Set count to 1 if no [Disc #] =%
    if !count! equ 0 set /a count=1

    flac.exe -0 --picture="!file!.jpg" --tag-from-file="CUESHEET=!file!.cue" -T "ALBUMARTIST=!artist!" -T "DISCNUMBER=!disc!" -T "TOTALDISCS=!count!" "!file!.wav"

    %= pop the setlocal stack to get back to state at beginning of loop =%
    endlocal
  )
)
popd

您可能想要添加一个检查以仅在 FLAC 文件尚不存在时才继续,这样您就可以多次 运行 脚本而无需重新处理文件。外循环看起来像这样,但我不能确定,因为我不知道输出文件名的格式:

for /f "delims=" %%A in ('dir /b /a-d "%source%\*.wav"') do if exist "%source%\%%~nA.jpg" if exist "%source%\%%~nA.cue" if not exist "%destination%\%%~nA.flac" (

如果您了解正则表达式,使用我的 JREPL.BAT utility 逻辑会简单得多:

@echo off
:: Delayed expansion must be disabled to protect ! when expanding FOR variables.
:: It is normally disabled by default, but I'm making it explicit, just to be sure.
setlocal disableDelayedExpansion

:: Define where source files are coming from
set "source=D:\music"

:: Define where output should be stored
set "destination=D:\music"

pushd "%destination%"


:: Iterate all *.wav and use JREPL to format result as "fullFileName|artist - album|artist|Disc#"
::                                                      %%A          %%B            %%C    %%D
:: Only proceed if .jpg and .cue also exist
for /f "tokens=1-4 delims=|" %%A in (
  'dir /b /a-d "%source%\*.wav"^|jrepl "^((.+?) - .+?)(?:\[Disc (\d+)])?\.wav$" "$&|||" /i'
) do if exist "%%~nA.jpg" if exist "%%~nA.cue" (

  %= disc and count are both 1 if %%D is empty =%
  if "%%D" equ "" (
    flac.exe -0 --picture="%source%\%%~nA.jpg" --tag-from-file="CUESHEET=%source%\%%~nA.cue" -T "ALBUMARTIST=%%C" -T "DISCNUMBER=1" -T "TOTALDISCS=1" "%source%\%%A"

  %= else count the number of .wav files =%
  ) else for /f %%E in ('dir /b /a-d "%%B[*.wav"^|find /c /v ""') do (
    flac.exe -0 --picture="%source%\%%~nA.jpg" --tag-from-file="CUESHEET=%source%\%%~nA.cue" -T "ALBUMARTIST=%%C" -T "DISCNUMBER=%%D" -T "TOTALDISCS=%%E" "%source%\%%A"
  )
)

popd

同样,您可以向外循环添加一个 IF,仅当目标中不存在 .flac 文件时才继续。