VideoHelp Forum




+ Reply to Thread
Results 1 to 10 of 10
  1. The purpose is to scan a given folder for media files are send the mediainfo to info.txt BUT also to giv user an option to scan only for files having a particular text string.
    My bat file:
    Code:
    @echo off
    setLocal EnableDelayedExpansion
    echo. >info.txt
    set /P "folder=Enter folder path: "
    set /P "_input=Search all files (y/n): "
    
    if /I "%_input%" == "y" (
    	dir %folder% /B /O:N | findstr /I ".wmv$ .mpg$ .mkv$ .mpeg$ .mp4$ .avi$" >filename.txt 
    	for /f "tokens=* delims= " %%a in ('type filename.txt') do ( 
    	set _in=%_in%%%a 
    	mediainfo --Inform=file://template.txt "%folder%!_in!" >>info.txt 
    	echo. >>info.txt 
    	)
    ) else ( 
    	set /P "_str=Enter file string: " 
    	dir %folder% /B /O:N | findstr /I "%_str%" >filename.txt
    	for /f "tokens=* delims= " %%a in ('type filename.txt') do ( 
    	set in=%in%%%a 
    	mediainfo --Inform=file://template.txt "%folder%!in!" >>info.txt 
    	echo. >>info.txt 
    	)
    )
    
    del filename.txt
    cls
    pause
    Though the first part of if loop works correctly but the 'else' part don't, I can't get the error because with a flicker of an eye it disappears & I can't troubleshoot it
    Quote Quote  
  2. CMD's behavior with nested commands can seem erratic at times. It gets more difficult to predict an outcome when external commands are involved.

    The old COMMAND ability to execute a batch line by line is sorely missing in CMD. One way to get to see error messages as they appear is to add a pause where you think the problem occurs. In your case you could just REM out the CLS.

    When troubleshooting more complex batches, I will open a CMD prompt and copy and execute each line one at a time. That makes it easy to see where to place the line breaks in nested commands. Also, issuing a SET followed by PAUSE, will let you see what your variables are doing.

    Ultimately, I find that it's preferable to use subroutines instead. In your case, it's just a matter of choosing the right thing to use IF with:

    Code:
    @echo off
    setLocal EnableDelayedExpansion
    echo. >info.txt
    set /P "folder=Enter folder path: "
    set /P "_input=Search all files (y/n): "
    
    if /I "%_input%" == "y" set _str=.wmv$ .mpg$ .mkv$ .mpeg$ .mp4$ .avi$
    if not /I "%_input%" == "y" set /P "_str=Enter file string: "
    
    dir %folder% /B /O:N | findstr /I "%_str%" >filename.txt
    
    for /f "tokens=* delims= " %%a in (filename.txt) do (
    set in=%in%%%a
    mediainfo --Inform=file://template.txt "%folder%!in!" >>info.txt
    echo. >>info.txt
    )
    
    del filename.txt
    cls
    pause
    Quote Quote  
  3. It's nice to talk about subroutines, but I guess an example would have been nice.

    Code:
    @echo off
    goto :START
    
    :INFO
    mediainfo --Inform=file://template.txt "%folder%!%%1!" >>info.txt
    echo. >>info.txt
    goto :EOF
    
    :START
    setLocal EnableDelayedExpansion
    echo. >info.txt
    set /P "folder=Enter folder path: "
    set /P "_input=Search all files (y/n): "
    
    if /I "%_input%" == "y" set _str=.wmv$ .mpg$ .mkv$ .mpeg$ .mp4$ .avi$
    if not /I "%_input%" == "y" set /P "_str=Enter file string: "
    
    dir %folder% /B /O:N | findstr /I "%_str%" >filename.txt
    
    for /f "tokens=* delims= " %%a in (filename.txt) do CALL :INFO %%a
    
    del filename.txt
    cls
    pause
    Quote Quote  
  4. Originally Posted by nic2k4 View Post
    It's nice to talk about subroutines, but I guess an example would have been nice.
    Thnx need some clarification on following lines:
    What does this do: CALL :INFO %%a
    What is: goto :EOF
    mediainfo --Inform=file://template.txt "%folder%!%%1!" >>info.txt is it %%a
    Quote Quote  
  5. To find out what a CMD shell command does, type the "command /?" at the prompt i.e. CALL /? You can also use this site as a reference.

    CALL is used to basically put the current batch file on hold while an external command is being executed then to return to the calling batch file at the point where call was issued. In CMD, CALL can also be used with LABELS, so you can run a batch inside the batch and return to where you left off.

    Here CALL says go to LABEL :INFO at the beginning of the batch file; %%a is the variable you defined in your FOR statement. The lines after :INFO are executed as if a new batch was being run, thus the value of %%a is read and understood to be the same as %1 in the mediainfo line.

    Think of the lines between :INFO and goto :EOF at the beginning of the file as a separate batch file. The FOR statement calls that batch with the value of %a as an argument. To that new batch it's like %a never existed, but arguments following a batch are recognized by the numerical variables %1, %2...

    GOTO :EOF means goto end of file. It's required when CALLing a LABEL to tell CMD that the "virtual batch file" ends here. It delimits the subroutine and causes it to exit back to where it was called from.

    GOTO :EOF always goes to the end of a batch; it's handy to end a batch without having to define a LABEL.
    Last edited by nic2k4; 1st Nov 2012 at 21:03.
    Quote Quote  
  6. @nic2k4
    Thnx for explaining but i am afraid thr are at least three things not right wth the script u gave:
    • Under win732bit whole of the script is breaking if i use if not
    • If a folder has three files Red,Green,Blued the output of ur script is such that its printed 3 times:
      Code:
       
      File is: Blued.avi
      Format: AVI 
      VideoFormat: MPEG-4 Visual
      CodecID: XVID
      Resolution: 512x384
      DAR: 4:3 or 1.333
      PAR: 1.000
      FrameMode: 
      VideoBitrateMode: 
      ScanType: Progressive
      AudioCodec: MPEG Audio
      AudioBitrateMode: CBRFile is: Green.avi
      Format: AVI 
      VideoFormat: MPEG-4 Visual
      CodecID: XVID
      Resolution: 512x384
      DAR: 4:3 or 1.333
      PAR: 1.000
      FrameMode: 
      VideoBitrateMode: 
      ScanType: Progressive
      AudioCodec: MPEG Audio
      AudioBitrateMode: CBRFile is: Red.avi
      Format: AVI 
      VideoFormat: VP6
      CodecID: VP6F
      Resolution: 320x240
      DAR: 4:3 or 1.333
      PAR: 1.000
      FrameMode: 
      VideoBitrateMode: 
      ScanType: 
      AudioCodec: MPEG Audio
      AudioBitrateMode: CBR
       
      File is: Blued.avi
      Format: AVI 
      VideoFormat: MPEG-4 Visual
      CodecID: XVID
      Resolution: 512x384
      DAR: 4:3 or 1.333
      PAR: 1.000
      FrameMode: 
      VideoBitrateMode: 
      ScanType: Progressive
      AudioCodec: MPEG Audio
      AudioBitrateMode: CBRFile is: Green.avi
      Format: AVI 
      VideoFormat: MPEG-4 Visual
      CodecID: XVID
      Resolution: 512x384
      DAR: 4:3 or 1.333
      PAR: 1.000
      FrameMode: 
      VideoBitrateMode: 
      ScanType: Progressive
      AudioCodec: MPEG Audio
      AudioBitrateMode: CBRFile is: Red.avi
      Format: AVI 
      VideoFormat: VP6
      CodecID: VP6F
      Resolution: 320x240
      DAR: 4:3 or 1.333
      PAR: 1.000
      FrameMode: 
      VideoBitrateMode: 
      ScanType: 
      AudioCodec: MPEG Audio
      AudioBitrateMode: CBR
       
      File is: Blued.avi
      Format: AVI 
      VideoFormat: MPEG-4 Visual
      CodecID: XVID
      Resolution: 512x384
      DAR: 4:3 or 1.333
      PAR: 1.000
      FrameMode: 
      VideoBitrateMode: 
      ScanType: Progressive
      AudioCodec: MPEG Audio
      AudioBitrateMode: CBRFile is: Green.avi
      Format: AVI 
      VideoFormat: MPEG-4 Visual
      CodecID: XVID
      Resolution: 512x384
      DAR: 4:3 or 1.333
      PAR: 1.000
      FrameMode: 
      VideoBitrateMode: 
      ScanType: Progressive
      AudioCodec: MPEG Audio
      AudioBitrateMode: CBRFile is: Red.avi
      Format: AVI 
      VideoFormat: VP6
      CodecID: VP6F
      Resolution: 320x240
      DAR: 4:3 or 1.333
      PAR: 1.000
      FrameMode: 
      VideoBitrateMode: 
      ScanType: 
      AudioCodec: MPEG Audio
      AudioBitrateMode: CBR
    • Third problem is tht no linebreak occurs before file name
    I am using:
    Code:
    @echo off
    goto :START
    
    :INFO
    mediainfo --Inform=file://template.txt "%folder%!%%1!" >>info.txt
    echo. >>info.txt
    goto :EOF
    
    :START
    setLocal EnableDelayedExpansion
    echo. >info.txt
    set /P "folder=Enter folder path: "
    set /P "_input=Search all files (y/n): "
    
    if /I "%_input%" == "y" set _str=.wmv$ .mpg$ .mkv$ .mpeg$ .mp4$ .avi$
    if /I "%_input%" == "n" set /P "_str=Enter file string: "
    
    dir %folder% /B /O:N | findstr /I "%_str%" >filename.txt
    
    for /f "tokens=* delims= " %%a in (filename.txt) do CALL :INFO %%a
    
    del filename.txt
    cls
    pause
    Quote Quote  
  7. Sorry, I didn't fully vet your code; besides I don't have all the parameters of what you're doing. You originally said everything was working until the ELSE loop, so I just copy/pasted what you did apart from what was the obvious problem that answered your original question.

    If I take a more serious look at it; look at the contents of FILENAME.TXT (so don't delete it at the end of the batch). You'll see that all the files are listed one per line and in alphabetical order, so you don't need to specify that the string to search for is at the end of a line (that's the $ in .AVI$ .MPG$...) (ok, it might be helpful if you get a filename like MOVIE.MPG.AVI, but personally I think the batch deserves to fail with such filenames).

    Next, if you test _input only for a N value the batch will crash when you accidentally hit B or M. The reason IF NOT didn't work is that the NOT was in the wrong place. Even then we're still looking for Y or N, any other key will crash the batch. There are many ways to prevent that:

    Code:
    :START
    echo. >info.txt
    set /P "folder=Enter folder path: "
    :OOPS
    cls
    set /P "_input=Search all files (y/n): "
    if /I not "%_input%" == "y" if /I not "%_input%" == "n" GOTO :OOPS
    if /I "%_input%" == "y" set _str=.wmv .mpg .mkv .mpeg .mp4 .avi
    if /I not "%_input%" == "y" set /P "_str=Enter file string: "
    or

    Code:
    :START
    echo. >info.txt
    set /P "folder=Enter folder path: "
    set /P "_input=Search all files (y/n): "
    if /I "%_input%" == "y" (
    set _str=.wmv .mpg .mkv .mpeg .mp4 .avi
    ) ELSE (
    set /P "_str=Enter file string: "
    )
    or

    Code:
    :START
    set _str=.wmv .mpg .mkv .mpeg .mp4 .avi
    echo. >info.txt
    set /P "folder=Enter folder path: "
    set /P "_input=Search all files (y/n): "
    if /I not "%_input%" == "y" set /P "_str=Enter file string: "
    Guess what happens with the last 2 examples if you input a W.

    You might have noticed I removed the delayedexpansion, most of the time you don't need it and it's mostly used inside a FOR loop. Also, the syntax was wrong: "%folder%!%%1!" should have been "%folder%!1!" if it was to be used. Except that %1 is always updated every time the subroutine is called. It would have made more sense to used it on %a (that is !a!), but again, the FOR command variable is always updated during the loop.

    When you see a result repeating with a FOR loop, it means your command is not parsing the way you expect. In your case the problem is the use of FOR /F. That command is used to separate the content of the fileset in brackets and output multiple variables according to the TOKEN and DELIMS parameters i.e. you could end up with %a %b %c... You set the TOKEN to *, you told the FOR command to take the contents of FILENAME.TXT and place it all inside 1 variable, hence you get the mediainfo results for all files with no separation in 1 bunch, but since there are 3 filenames to process by FOR it repeats 3 times. This is what you need to use:

    Code:
    for %%a in (filename.txt) do CALL :INFO %%a
    ECHO %%1 just after the :INFO label would have helped you troubleshoot that. You can copy and paste lines into a command prompt box to see if the code works as you expect, use SET to view variables and explorer to view the content of any files you generate. Just remember to remove one % sign from variables when you paste a line.
    Quote Quote  
  8. so...i am desperate to understand how this all works & I gratify you for providing time to make me understand.
    Let me split the bat file because till the filename.txt creation everything works fins its the naughty for loop & subroutine connection that is absurd...
    This part is ok & is thus skipped

    Code:
    @echo off
    goto :START
    
    :INFO
    mediainfo --Inform=file://template.txt "%folder%!a!" >>info.txt
    echo. >>info.txt
    goto :EOF
    
    :START
    setLocal EnableDelayedExpansion
    echo. >info.txt
    set /P "folder=Enter folder path: "
    set /P "_input=Search all files (y/n): "
    if /I "%_input%" == "y" set _str=.wmv$ .mpg$ .mkv$ .mpeg$ .mp4$ .avi$
    if /I not "%_input%" == "y" set /P "_str=Enter file string: "
    dir %folder% /B /O:N | findstr /I "%_str%" >filename.txt
    Now we have a filename.txt with the following info
    Code:
    Blued.avi
    Green.avi
    Red.avi
    Now we only deal with this text file with other part/variables skipped, the new bat to teach myself the working is follows. Following Works! with correct output but one limitation discussed below

    Code:
    echo. >info.txt
    @echo on
    echo. >info.txt
    goto :START
    
    :INFO
    mediainfo --Inform=file://template.txt "d:movies/%1" >>info.txt
    echo. >>info.txt
    goto :EOF
    
    :START
    for /f "tokens=* delims= " %%a in (filename.txt) do call :INFO %%a
    
    pause
    Also for mediainfo to work, the cli is
    Code:
    mediainfo --Inform=file://template.txt "d:movies/{name of media file with extension}" >>info.txt
    Thus, our for loop should run three times (because there are three lines in the txt file) & each time should send the text string in line1, then line2, then line3 & shouldn't concatenate the strings at different lines. According to http://ss64.com/nt/for_f.html "tokens=* delims= " are right for this job, unlike you said?

    The limitation I was talking about - For instance if our filename.txt contains a name with spaces in it
    Code:
    Blued the.avi
    Green.avi
    Red.avi
    above mentioned code willnt work for the first file bcz %%a=%1=Blue & not Blue the.avi no matter whether I omit tokens & delimiters this 'space issue' retains. I discovered (google is friend) replacing %1 with %* (concatenate all arguments) fixes this issue
    Code:
    mediainfo --Inform=file://template.txt "d:movies/%*" >>info.txt
    Now my question why this space problem didn't arose when I use this code
    Code:
    @echo off
    setLocal EnableDelayedExpansion
    echo. >info.txt
    set /P "folder=Enter folder path: "
    set /P "_input=Search all files (y/n): "
    
    if /I "%_input%" == "y" set _str=.wmv$ .mpg$ .mkv$ .mpeg$ .mp4$ .avi$
    if not /I "%_input%" == "y" set /P "_str=Enter file string: "
    
    dir %folder% /B /O:N | findstr /I "%_str%" >filename.txt
    
    for /f "tokens=* delims= " %%a in (filename.txt) do (
    set in=%in%%%a
    mediainfo --Inform=file://template.txt "%folder%!in!" >>info.txt
    echo. >>info.txt
    )
    
    del filename.txt
    cls
    pause
    Quote Quote  
  9. This is weird I posted a reply to this last morning; oh well, here we go again.

    According to http://ss64.com/nt/for_f.html "tokens=* delims= " are right for this job, unlike you said?
    SS64 is the reference, they're right and you're right. I was thinking of something else, I should refer to SS64 more often.

    The reason this
    Code:
    for /f "tokens=* delims= " %%a in (filename.txt) do (
    set in=%in%%%a
    mediainfo --Inform=file://template.txt "%folder%!in!" >>info.txt
    echo. >>info.txt
    )
    is not affected by spaces in the name is tokens=* and the use of double quote character ("). That means that when FOR /F reads a line in filename.txt, every items it finds will be sent to a single variable (%a). Here you specified that each item is separated by a space (delims= ). BTW, if you don't specify delims they default to spaces and tabs. So, when the filename BLUE THE.AVI is read and passed to %a the set command loads it into variable in. Long file names must be surrounded by double quotes like you did for the path on the mediainfo line ("%folder%!in!").

    One thing I find odd with the code above, set in=%in%%%a, this form is used to keep adding to a variable without losing the previous contents. I'm not sure that during a FOR loop this would happen, but at the last iteration the variable in should include all the previous values of %a. I think it should be set in=%%a.

    In this
    Code:
    :INFO mediainfo --Inform=file://template.txt "d:movies/%1" >>info.txt
    echo. >>info.txt
    goto :EOF
    
    :START for /f "tokens=* delims= " %%a in (filename.txt) do call :INFO %%a
    the FOR loop works the same as above and the command would be call :INFO BLUE THE.AVI. Since everything after the label being called is treated as a parameter and spaces separate parameters, we end up with 2 parameters and since the path on the mediainfo line (d:movies/%1) only includes 1 parameter (BLUE), mediainfo can't find the file and fails. "d:movies/%1 %2" would have worked, but not if there were 6 parameters. Another problem is you can only go up to %9, beyond that you have to use the shift command and that's really not practical. As you found out %* is the solution.

    Shouldn't the mediainfo path be "d:\movies\%*"? Mind the slashes when you input the folder name. You might be better off with hard coding the slashes, as in "%folder%\!in!", then you would only type d:\movies when prompted for the folder.

    There are many ways to arrive at the same results, whether you're using subroutines or nested commands, both should work.
    Last edited by nic2k4; 3rd Nov 2012 at 23:28.
    Quote Quote  
  10. Thank you very much nick,
    you proved to be a devote teacher for a noob like me, now I understand fully.
    On a side note I have PMed you hope you reply soon.
    Quote Quote  



Similar Threads

Visit our sponsor! Try DVDFab and backup Blu-rays!