Log in

View Full Version : Batch script - for loop with spaces in files/folder name & drag-and-drop file+folder


Reino
28th August 2013, 23:20
Hi,

@ECHO OFF

SET pathToFFmpeg="D:\Binaries\ffmpeg-20130824-git-88909be.exe"

FOR /F "delims=" %%A IN (%*) DO (
IF NOT EXIST "%%~dpnA.mp3" %pathToFFmpeg% -i "%%A" -vn -c:a libmp3lame -q:a 5 -id3v2_version 3 "%%~dpnA.mp3"
)I've made this batch-script (altered actually (http://ffmpeg.zeranoe.com/forum/viewtopic.php?f=17&t=957)) to drag-and-drop media files onto to be encoded to mp3 with FFmpeg. Now the problem is spaces in files/folder names together with /F "delims=".
Let's say we have "sample1.flac" and "sample2.flac" in "D:\Audio\". Dropping these 2 files on the batch-script without /F "delims=" works just fine, but fails when the 2 flac-files reside in "D:\Audio samples\FLAC samples\" and are named "flac sample1.flac" and "flac sample2.flac", because of the spaces.
That's where /F "delims=" comes in. Dropping 1 file on the batch-script with /F "delims=" works fine, but fails when dropping 2 (or more) flac-files. FFmpeg asks if I want to overwrite the dropped 2 flac-files! :confused: What's going on here?

The weird thing is...
@ECHO OFF

SET pathToFFmpeg="D:\Binaries\ffmpeg-20130824-git-88909be.exe"

:loop
IF "%~1"=="" GOTO end
%pathToFFmpeg% -i %1 -vn -c:a libmp3lame -q:a 5 -id3v2_version 3 "%~dpn1.mp3"
SHIFT
GOTO loop
:end
PAUSE...dropping multiple files on this one, and I end up with perfectly encoded mp3-files.
What does a FOR loop need to produce the same results?

Eventhough I'm stuck with this issue, in the end I wanted to create a batch-script where I could also drop a folder onto, so FFmpeg would encode all the files inside.
I did a lot of searching and eventually landed here (http://stackoverflow.com/questions/10960165/batch-script-drag-and-drop-folder-convert-images-with-imagemagick).

@ECHO OFF

SET pathToFFmpeg="D:\Binaries\ffmpeg-20130824-git-88909be.exe"

FOR /F "delims=" %%A IN (%*) DO (
IF EXIST %%A (
IF EXIST %%A\ (
FOR /F "delims=" %%F IN (%%A\*) DO (
IF NOT EXIST "%%~dpnA.mp3" %pathToFFmpeg% -i "%%~F" -vn -c:a libmp3lame -q:a 5 -id3v2_version 3 "%%~A\%%~dpnF.mp3"
)
) ELSE (
IF NOT EXIST "%%~dpnA.mp3" %pathToFFmpeg% -i "%%~A" -vn -c:a libmp3lame -q:a 5 -id3v2_version 3 "%%~dpnA.mp3"
)
) ELSE (
ECHO Skipping non-existent %%~A
)
)
PAUSE
...but since I'm stuck with the spaces-issue, I don't even know if this is the right approach.
If someone knows how to let the script accept spaces in files/folder names in all situations, please point me in the right direction.

Sparktank
28th August 2013, 23:39
I remember for instances where spaces were used (or even folder\file names being more than 8 characters), I converted them to... "short name".

Let's use "sox 14.4.1a" for example path I want.

"C:\Apps\Audio\sox 14.4.1a\sox.exe"

Batch will accept better...

"C:\Apps\Audio\SOX144~1.1A\sox.exe"

You can find the short name for directories/files using CMD with "dir /x"
/X This displays the short names generated for non-8dot3 file
names. The format is that of /N with the short name inserted
before the long name. If no short name is present, blanks are
displayed in its place.

/N New long list format where filenames are on the far right.

open CMD, change dir to where non-8dot3 file name is and run "dir /x" to get short name.


cmd
cd /d C:\Apps\Audio
dir /x
(copy short name)


The other alternative is to rename everything to avoid spaces, or even that everything is equal or less than 8 characters.

I believe there is another way to write it out in batch that is much easier, but I'm not that crafty with batchy.
Someone will surely come along and enlighten (us both; I know I could probably use more info on batching).

mastrboy
28th August 2013, 23:42
For batch to accept spaces the filename/foldername need to be encapsulated inside "", for example "file with space.ext", if you need to use double, like """", I think you need to escape it with ^ (If I remember correctly)...

Rather than struggling with fugly batch, you should just put your efforts into powershell instead...

Reino
2nd January 2017, 00:21
Found this old thread of mine. I still don't have much experience with PowerShell, but managing batchscripts is going much better than when I started this thread. So in order to help other visitors of this thread looking for a drag&drop-script, I thought I'd answer my own question:
@ECHO OFF

SET ffmpeg="D:\Storage\Media\Binaries\FFmpeg\ffmpeg.exe"

FOR %%A IN (%*) DO (
FOR /F "delims=-" %%B IN ("%%~aA") DO (
IF "%%B"=="d" (
FOR %%C IN ("%%~A\*.flac") DO (
IF NOT EXIST "%%~dpnC.mp3" %ffmpeg% -hide_banner -i "%%C" -c:a libmp3lame -q:a 5 -id3v2_version 3 "%%~dpnC.mp3"
)
) ELSE IF "%%~xA"==".flac" (
IF NOT EXIST "%%~dpnA.mp3" %ffmpeg% -hide_banner -i %%A -c:a libmp3lame -q:a 5 -id3v2_version 3 "%%~dpnA.mp3"
)
)
)
PAUSE
- When looping over %* (files and folders) one shouldn't use the /F switch. The /F switch is for parsing strings, command-outputs and text files.
- Then you'd have to find a way to check whether the input is a file, or a folder. IF EXIST %%A\ (...) ELSE (...) works for local files and folders, but not for network paths. Checking the file attributes on the other hand should work in all situations (thanks to dbenham's answer on Stack Overflow (https://stackoverflow.com/a/8669636/2703456)). A file returns --a------, while a folder returns d--------.
- If the input is a folder, then the FOR-loop to loop over its content again shouldn't contain the /F switch.
With ("%%~A\*.flac") you can filter the files you want to process.
The variable %%C from this FOR-loop needs surrounding double-quotes in the FFMpeg-command
- If the input are files, then with IF "%%~xA"==".flac" you can filter the files you want to process.
The variable %%A doesn't need surrounding double-quotes in the FFMpeg-command.
- As far as I can tell you can't drag&drop non-existing files, so there's no need for another if-statement.

You can safely drag&drop files and folders (locally, or on your network) on this batchscript and only flac-files will be processed.
Simply change .flac and the FFMpeg-commands accordingly if you want to process other files, or only change the FFMpeg-commands if you want encode to another audio-format.


Above batchscript doesn't work with read-only folders.
Read-only folders are actually a rare phenomenon, because the "Read-only"-checkbox in the folder-properties, contrary to what you might expect, applies to the content of the folder and not the folder itself.
In order to actually set the read-only attribute for the folder you'd have to run attrib +r [drive:][path], which nobody does afaik. So a rare use-case.
Nevertheless, the following batchscript will detect those too:
@ECHO OFF

SET ffmpeg="D:\Storage\Media\Binaries\FFmpeg\ffmpeg.exe"

FOR %%A IN (%*) DO (
FOR /F "tokens=1,2 delims=d" %%B IN ("-%%~aA") DO (
IF NOT "%%C"=="" (
FOR %%D IN ("%%~A\*.flac") DO (
IF NOT EXIST "%%~dpnD.mp3" %ffmpeg% -hide_banner -i "%%D" -c:a libmp3lame -q:a 5 -id3v2_version 3 "%%~dpnD.mp3"
)
) ELSE IF "%%~xA"==".flac" (
IF NOT EXIST "%%~dpnA.mp3" %ffmpeg% -hide_banner -i %%A -c:a libmp3lame -q:a 5 -id3v2_version 3 "%%~dpnA.mp3"
)
)
)
PAUSE

ndjamena
2nd January 2017, 02:20
A file does not necessarily return --a in it's attributes, the 'a' is the archive bit, which just means the file hasn't been backed up since last created/modified.

https://en.wikipedia.org/wiki/Archive_bit
http://ss64.com/nt/syntax-args.html

tebasuna51
2nd January 2017, 12:49
@ndjamena
Yep, but "The operating system never clears the archive bit on its own, unless explicitly told to do so by the user"

Then is only a warning for expert users than use some incremental backup system, for common users that must work always.

ndjamena
2nd January 2017, 13:41
His actual script checks for the 'd' flag and assumes a file if it's not present. Unless there are path targets other than files or directories that would be the correct method.

tebasuna51
2nd January 2017, 16:16
Files dragged over the script without any attribute set ("---------") are ignored by the

FOR /F "delims=-" %%B IN ("%%~aA") DO (
...

and aren't processed.

Reino
2nd January 2017, 16:38
The alternative script also detects files without any attribute.

...path targets other than files or directoriesFiles, folders and network paths. What else is there?

ndjamena
2nd January 2017, 16:48
Personally I think attempting to do all this within for loops is too constraining to be recommended. If anyone reading wants to do anything more complicated then shown they're going to have to completely reconfigure the script.

(CALL is your friend, although using EnableDelayedExpansion everywhere is acceptable in some circles.)

ndjamena
2nd January 2017, 16:50
Just covering my ass in case there are things I don't know... although don't COM serial ports have paths?.. Not sure.

Reino
2nd January 2017, 16:55
My hobby-project BatchGemist (https://github.com/Reino17/BatchGemist/blob/master/batchgemist-1.52b_no-powershell.bat); LOTS of FOR-loops, quite some EnableDelayedExpansions, but not CALLs. Runs pretty smooth.

ndjamena
2nd January 2017, 16:56
Here we go, write this in the command prompt:

for %g in ("\\.\pipe\*") do echo %~ag

They don't have any attributes though...

Reino
2nd January 2017, 17:22
Who on earth would want to run the script above with that as input?
The aim for the script is first of all drag&drop and you can't drag something like that onto a bat-file. If the aim was run from the command-prompt (file.bat "[file or folder]"), then another if-statement to check whether the input exists would indeed be helpful.

ndjamena
2nd January 2017, 18:12
I thought we were talking about things that weren't files or directories.

What else is there? And whatnot.