-3

I wrote a script in bash. That script is making a file with extension .DAT File getting details from mp3 files. I used exiftool to take id3 tags. I have a mp3 file called Miley Cyrus - Wrecking Ball.mp3 this script making file Miley Cyrus - Wrecking Ball.DAT which contain some details form ID3 tags.

My script in bash.

#!/bin/bash 
find . -name '*.mp3' -print0 | while read -d $'\0' file
do

ARTIST=$(exiftool -p '$Artist' "$file")
ALBUM=$(exiftool -p  '$Album' "$file")
TITLE=$(exiftool -p '$Title'  "$file")

touch "$file".DAT

echo "Lit=" >> "$file".DAT
echo "ENG=" >> "$file".DAT
echo "CRD=" >> "$file".DAT
echo "TIT=$TITLE" >> "$file".DAT
echo "ALB=$ALBUM" >> "$file".DAT
echo "ART=$ARTIST" >> "$file".DAT

done

I need that script but in windows, and here starts my troubles. I have no idea which way can I start with it. Which options I have to use for loop, why exiftool no getting tags from file? I tried to use fname to separate name and extension but with no results.

  1. What I need to do for start working in windows this scripts.
@echo off 

setlocal enableDelayedExpansion 

for %%a in (*.mp3) do (

 set "Title=(exiftool -p Title '%%a')"
 set "Album=(exiftool -p Album '%%a')"
 set "Artist=(exiftool -p Artist '%%a')"


echo "Lit=" >> "%%a".DAT
echo "ENG=" >> "%%a".DAT
echo "CRD=" >> "%%a".DAT
echo "Title=%Title% >> "%%a".DAT
echo "Album=%Album% >> "%%a".DAT
echo "Artist=%Artist% >> "%%a".DAT
)

exiftool is in windows folder.

Remik
  • 1
  • 1
  • Is the '.DAT' file always appended to, or should it be new every time? – lit Jun 28 '20 at 19:36
  • Welcome to SO, @Remik. This question is quite broad. SO tends to want to put laser focus on only one (1) issue at a time. One way to address this would be to write it as a pwsh script. That would allow the same code to be run on Linux, Mac, Windows, etc. http://www.github.com/PowerShell/PowerShell – lit Jun 28 '20 at 20:06
  • Should be new for every mp3 in folders, because another program using the DAT file. Bash script doing it perfect but that program working only on windows. – Remik Jun 28 '20 at 20:08
  • 2
    to capture the output of a command into a variable, use [for /f](https://ss64.com/nt/for_cmd.html). And you'll need [delayed expansion](https://stackoverflow.com/questions/30282784/variables-are-not-behaving-as-expected/30284028#30284028) – Stephan Jun 28 '20 at 20:19
  • This question should be reopened. Yes, it is quite broad, but is is not a flat out request to convert bash into cmd. – lit Jun 28 '20 at 21:00
  • 1
    This is more effort than I usually see for a bash-to-batch question. Good job. It seems like your only real issue is figuring out how to store the output of commands in variables, which can be found [here](https://stackoverflow.com/questions/11569436/how-to-store-output-of-command-in-variable-in-cmd). – SomethingDark Jun 28 '20 at 21:12

3 Answers3

1

I'm not familiar with exiftool, so I can't verify, but the following should work:

@echo off 
setlocal enabledelayedexpansion
for %%a in (*.mp3) do (
  for /f "usebackq delims=" %%b in (`exiftool -p Title '%%a'`) do set "title=%%b"
  for /f "usebackq delims=" %%b in (`exiftool -p Album '%%a'`) do set "Album=%%b"
  for /f "usebackq delims=" %%b in (`exiftool -p Artist '%%a'`) do set "Artist=%%b"
  (
    echo Lit=
    echo ENG=
    echo CRD=
    echo Title=!title!
    echo Album=!Album!
    echo Artist=!Artist!
  ) > "%%~dpna.dat"
)

Note: if the filenames or strings contain exclamation mark(s), you run into problems due to delayed expansion.
If you want to avoid delayed expansion (for this or any other reason), you can nest the for loops and use the metavariables directly:

@echo off 
for %%a in (*.mp3) do (
  for /f "usebackq delims=" %%b in (`exiftool -p Title '%%a'`) do (
    for /f "usebackq delims=" %%c in (`exiftool -p Album '%%a'`) do (
      for /f "usebackq delims=" %%d in (`exiftool -p Artist '%%a'`) do (
        (
          echo Lit=
          echo ENG=
          echo CRD=
          echo Title=%%b
          echo Album=%%c
          echo Artist=%%d
        ) > "%%~dpna.dat"
      )
    )
  )
)
Stephan
  • 53,940
  • 10
  • 58
  • 91
1

Instead of performing three individual EXIFTool iterations for each MP3 file, you should be able to do it with just one. In addition to that you shouldn't need to first select the *.mp3 files, as EXIFTool can already select all in the directory.

For example:

@For /F Tokens^=2^,4Delims^=^" %%G In (
    'EXIFTool *.mp3 -j -album -artist -title 2^>NUL^|%__AppDir__%find.exe ":"'
)Do @(Set "%%G=%%H"&SetLocal EnableDelayedExpansion&(Echo "Lit="&Echo "ENG="
        Echo "CRD="&Echo "TIT=!Title!"&Echo "ALB=!Album!"&Echo "ART=!Artist!"
    )>"!SourceFile:~,-4!.DAT"&EndLocal)

Assumed output example: (13 Come Said The Boy.DAT)

"Lit="
"ENG="
"CRD="
"TIT=Come Said The Boy"
"ALB=Just Great Australian Rock Songs Disc 2"
"ART=Mondo Rock"
Compo
  • 36,585
  • 5
  • 27
  • 39
  • I wondered if `exiftool` would have these features, but wasn't curious enough to download and install it. This is definitively a better approach. – Stephan Jun 29 '20 at 14:46
  • I took a quick look at its command line usage information, that's all @Stephan. I did that because I honestly couldn't envisage this command not being able to output more than one item in a single pass. I have had to assume that the JSON output would be easier to parse, _(and because it's apparently more efficient)_, as it should be doublequoted, and guessed the rest, because I'm still not a Windows PC owner, _(and none of the repair units I have contain `EXIFTool`)_. – Compo Jun 29 '20 at 16:02
0

Writing this as a pwsh script would allow the same script to be run on Linux, Mac, Windows, and others. http://www.github.com/PowerShell/PowerShell/

#!/bin/env pwsh
function touch {
    Param(
        [Parameter(Mandatory=$true)]
        [string]$Path
    )

    if (Test-Path -LiteralPath $Path) {
        $NewDate = Get-Date
        (Get-Item -Path $Path).LastWriteTime = $NewDate
        (Get-Item -Path $Path).LastAccessTime = $NewDate
    } else {
        New-Item -Type File -Path $Path
    }
}

$Cwd = Get-Location
$nl = [System.Environment]::NewLine

Get-ChildItem -Recurse -File -Path $Cwd -Filter '*.mp3' |
    ForEach-Object {
        $TITLE = & exiftool -charset filename=cp1250 -p '$Title' $_.FullName
        $ALBUM = & exiftool -charset filename=cp1250 -p '$Album' $_.FullName
        $ARTIST = & exiftool -charset filename=cp1250 -p '$Artist' $_.FullName

        $DataFile = Join-Path -Path $_.Directory -ChildPath $($_.BaseName + '.DAT')
        if (Test-Path -Path $DataFile) { Remove-Item -Path $DataFile }
        touch $DataFile

        "Lit=${nl}lENG=${nl}CRD=${nl}Title=$TITLE${nl}Album=$ALBUM${nl}Artist=$ARTIST" |
            Out-File -FilePath $DataFile -Encoding ascii
    }

I am not sure that a touch operation is needed. If the .DAT file exists, it will be overwritten. If it does not exist, it will be created. If so...

$Cwd = Get-Location
$nl = [System.Environment]::NewLine

Get-ChildItem -Recurse -File -Path $Cwd -Filter '*.mp3' |
    ForEach-Object {
        $TITLE = & exiftool -charset filename=cp1250 -p '$Title' $_.FullName
        $ALBUM = & exiftool -charset filename=cp1250 -p '$Album' $_.FullName
        $ARTIST = & exiftool -charset filename=cp1250 -p '$Artist' $_.FullName

        $DataFile = Join-Path -Path $_.Directory -ChildPath $($_.BaseName + '.DAT')

        "Lit=${nl}lENG=${nl}CRD=${nl}Title=$TITLE${nl}Album=$ALBUM${nl}Artist=$ARTIST" |
            Out-File -FilePath $DataFile -Encoding ascii
    }
lit
  • 14,456
  • 10
  • 65
  • 119
  • @litThese lines of code where is exiftool given back some errors (about code page). I had add a cp1250. Other problems been with ID3 tag. Your code given back the word what is in code. It needed Dollar sign '$' *** $TITLE = & exiftool -charset filename=cp1250 -p '$Title' $_.FullName $ALBUM = & exiftool -charset filename=cp1250 -p '$Album' $_.FullName $ARTIST = & exiftool -charset filename=cp1250 -p '$Artist' $_.FullName – Remik Jun 30 '20 at 10:24
  • Your encoding output to file is ASCII and ends line with Unix LF. I'm trying change ASCII to ANSI and ends lines form Unix LF into Windows CR LF I can't doing it. I used google for answer how I can do it? But most answers is into UTF8. Do you know solution of that problem? The program what reading the file do not see files with other code page than windows-1250. – Remik Jun 30 '20 at 10:24
  • My apologies. I changed the output to us 0x0D0A lline endings. Perhaps is would be better to output these lines separately so that they get the line ending native to the platform. Or, maybe pwsh has a variable for line ending... – lit Jun 30 '20 at 12:45
  • Changed output to use the system native newline. – lit Jun 30 '20 at 13:01