问题描述
我有几十个json文件,我试图在每个文件中找到两个值,并将结果分配给两个单独的变量,以进行ffmpeg处理。
{
"year": "2018","track": "12",... other data omitted
}
我希望提取2018和12,以便可以在以下ffmpeg命令中使用它们:
ffmpeg -i "same_file_name_as_json.m4a" -Metadata:s:a:0 year=2018 --Metadata:s:a:0 track=12 -acodec libmp3lame "same_file_name_as_json.mp3"
是否可以编写单个批处理文件来获得所需的结果?任何帮助将不胜感激,因为我是findstr和设置变量的新手。谢谢。
已编辑:
set "year=" & set "track="
for %%i in (*.json) do (
for /f "usebackq tokens=1,2 delims={:}," %%a in ("%%i") do (
set "%%~a=%%~b"
if defined year if defined track goto :CONT
)
:CONT
C:\ffmpeg -i "%%~ni.m4a" -Metadata:s:a:0 year=%year% -Metadata:s:a:0 track=%track% -acodec libmp3lame "%%~ni.mp3"
)
pause
解决方法
Windows批处理脚本不了解JSON文件格式,因此最好使用本机支持的语言。将JSON视为“普通”文本不是最好的主意,因为只有一点不违反JSON格式的更改(例如,添加,删除或移动的换行符)仍然会造成很大的麻烦。>
也就是说,假设JSON文件完全按照您显示的样子显示,并且具有Unix或DOS / Windows风格的换行符(即回车符和换行符),该代码可以为您工作:
for /F "usebackq tokens=1,2 delims={:}," %%M in ("file.json") do set "%%~M=%%~N"
echo year = %year%
echo track = %track%
如果您有一个巨大的JSON文件,不想不必要地进行完全处理,则可以改用以下代码:
set "year=" & set "track="
for /F "usebackq tokens=1," %%M in ("file.json") do (
set "%%~M=%%~N"
if defined year if defined track goto :CONT
)
:CONT
echo year = %year%
echo track = %track%
如果要提取的(非数组)值也可能包含定义的定界符之一({
,:
,}
,,
, SPACE ),您可以将代码扩展为此,因为值不包含字符*
,?
,<
,>
:
set "year=" & set "track="
for /F "usebackq tokens=1,* delims={:}," %%M in ("file.json") do (
for %%K in (%%N) do set "%%~M=%%~K"
if defined year if defined track goto :CONT
)
:CONT
echo year = %year%
echo track = %track%
要防止脚本分配不必要的多余变量,您可以尝试以下操作:
for /F "usebackq tokens=1," %%M in ("file.json") do (
if "%%~M"=="year" (set "%%~M=%%~N") else if "%%~M"=="track" set "%%~M=%%~N"
)
echo year = %year%
echo track = %track%
或者通过findstr
命令预先识别数据并过滤出所需的行:
for /F "tokens=1," %%M in ('
findstr /R /C:"^ *\"year\" *:" /C:"^ *\"track\" *:" "file.json"
') do set "%%~M=%%~N"
echo year = %year%
echo track = %track%
基于您的edit,让我建议使用上述方法中的最后一种,因为没有goto :CONT
,因为它会破坏块上下文,因此无法在循环中使用,并且确实不分配其他不需要的变量。由于变量是在循环体内写入和读取的,因此您必须启用并应用delayed variable expansion。我将通过以下方式进行所有操作:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem /* Iterate over the `*.json` files in the current working directory (`%CD%`);
rem to use the parent directory of this script,use `%~dp0*.json` instead: */
for %%I in ("*.json") do (
rem // Store name of current JSON file in variable:
set "name=%%~nI"
rem // Clear variables for later check for availability:
set "year=" & set "track="
rem // Process the current JSON file:
for /F "tokens=1," %%M in ('
findstr /R /C:"^ *\"year\" *:" /C:"^ *\"track\" *:" "%%~I"
') do (
rem // Assign year and track variables:
set "%%~M=%%~N"
rem // Check of both year and track are available:
if defined year if defined track (
rem // Toggle delayed expansion to avoid troubles with `!`:
setlocal EnableDelayedExpansion
rem // Eventually execute `ffmpeg` tool using all the derived data:
ffmpeg -i "!name!.m4a" -metadata:s:a:0 year=!year! -metadata:s:a:0 track=!track! -acodec libmp3lame "!name!.mp3"
endlocal
)
)
)
endlocal
exit /B
,
我有几十个json文件...
Windows的cmd
不支持JSON,因此您必须诉诸PowerShell或使用支持此功能的外部工具。您可能会发现xidel有趣。
要提取“年份”和“曲目”的值:
xidel -s input.json -e "$json/(year,track)"
#or
xidel -s input.json -e "$json/year,$json/track"
2018
12
要导出到变量%year%
和%track%
:
FOR /F "delims=" %A IN ('xidel -s input.json -e "$json/(year:=year,track:=track)" --output-format^=cmd') DO %A
#or
FOR /F "delims=" %A IN ('xidel -s input.json -e "year:=$json/year,track:=$json/track" --output-format^=cmd') DO %A
但是,您不需要变量来创建所需的字符串(ffmpeg
命令)。 xidel
也可以做到这一点。
您可以使用FOR
循环遍历所有JSON文件...
FOR %A IN (*.json) DO @xidel -s %A -e "$json/concat('ffmpeg -i \"%~nA.m4a\" -metadata:s:a:0 year=',year,' --metadata:s:a:0 track=',track,' -acodec libmp3lame \"%~nA.mp3\"')"
ffmpeg -i "name-of-json-file.m4a" -metadata:s:a:0 year=2018 --metadata:s:a:0 track=12 -acodec libmp3lame "name-of-json-file.mp3"
...但是为每个JSON文件调用xidel
效率很低。 xidel
可以更有效地做到这一点。xidel
与FOR %A IN (*.json) DO @ECHO %A
等效为xidel -se "file:list(.,false(),'*.json')"
然后,您可以使用以下查询一次处理所有JSON文件:
xidel -se "for $x in file:list(.,'*.json') return json-doc($x)/concat('ffmpeg -i \"',replace($x,'json','m4a'),'\" -metadata:s:a:0 year=',' -acodec libmp3lame \"','mp3'),'\"')"
预设的命令/查询:
xidel -se ^"^
for $x in file:list(.,'*.json') return^
json-doc($x)/concat(^
'ffmpeg -i \^"',^
replace($x,^
'\^" -metadata:s:a:0 year=',^
year,^
' --metadata:s:a:0 track=',^
track,^
' -acodec libmp3lame \^"',^
'\^"'^
)^
"