I have dozens of json files, and I am trying to find two values in each of them and assign the results to two separate variables for ffmpeg processing.
An example json file looks like this:
{
"year": "2018",
"track": "12",
... other data omitted
}
I wish to extract 2018 and 12 so that I can use them in the following ffmpeg command:
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"
Is it possible to write a single batch file to achieve the desired result? Any help would be greatly appreciated as I am a complete novice at findstr and setting variables. Thank you.
EDITED:
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 batch scripting does not understand the JSON file format, so it is better to use a language natively supports it. It is not the best idea to treat JSON as "normal" text, because only a slight change (for instance, added, deleted, or moved line-breaks) that do not violate the JSON format can still make big troubles then.
That said, given that the JSON file exactly appears as you have shown it and it features Unix- or DOS/Windows-style line-breaks (that is, a carriage-return character followed by a line-feed character), this code could work for you:
for /F "usebackq tokens=1,2 delims={:}, " %%M in ("file.json") do set "%%~M=%%~N"
echo year = %year%
echo track = %track%
If you have got a huge JSON file you do not want to unnecessarily fully process, you could use this code instead:
set "year=" & set "track="
for /F "usebackq tokens=1,2 delims={:}, " %%M in ("file.json") do (
set "%%~M=%%~N"
if defined year if defined track goto :CONT
)
:CONT
echo year = %year%
echo track = %track%
If the (non-array) values you want to extract may also contain one of the defined delimiters ({
, :
, }
, ,
, SPACE), you could extend the code to this, given that the values do not contain the characters *
, ?
, <
, >
:
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%
To prevent the script from assigning unwanted superfluous variables, you may try this:
for /F "usebackq tokens=1,2 delims={:}, " %%M in ("file.json") do (
if "%%~M"=="year" (set "%%~M=%%~N") else if "%%~M"=="track" set "%%~M=%%~N"
)
echo year = %year%
echo track = %track%
Or this, which prepreocesses the data by the findstr
command and filters out the desired lines:
for /F "tokens=1,2 delims={:}, " %%M in ('
findstr /R /C:"^ *\"year\" *:" /C:"^ *\"track\" *:" "file.json"
') do set "%%~M=%%~N"
echo year = %year%
echo track = %track%
Based on your edit, let me suggest to use the last of the above methods, because there is no goto :CONT
, which cannot be used within loops as it breaks the block context, and it does not assign additional unwanted variables. Since variables are written and read within the loop body, you have to enable and apply delayed variable expansion. I would do all that the following way:
@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,2 delims={:}, " %%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