4

I'm attempting to pick a random 100 songs to copy to my mp3 player so I have something new to listen to each morning without having to drag and drop random files myself (I can't put my entire library on the player at once).

I'm using a bat script to do it but I've encountered a few snags. The one I have below works, but copies ALL the files in a random folder rather than a random file from a random folder before moving on to the next.

I'm a complete novice with this so everything is kinda culled from other solutions on here and bodged together.

echo off
:randomstart
setlocal EnableDelayedExpansion
rem Enter into the directory that contain the folders
pushd D:\test1\
rem Create an array with all folders
set i=0
for /D %%a in (*) do (
   set /A i+=1
   set folder[!i!]=%%a
)
rem Randomly select one folder
set /A index=(%random%*i)/32768 + 1
rem Copy the desired file
copy "!folder[%index%]!\" "D:\output2\" /Y
rem And return to original directory
popd
ping -n 2 localhost >nul
goto:randomstart

I've also tried adding a for loop to count from 1 to 100 but I can't get my head around it in the slightest. Is there anyone out there that can save this idiot?

I tried asking this on Server fault and was told this would be a better place to ask.

5
  • What version of windows are you using, can you use powershell instead of batch files, Powershell is a lot easier to work with and is included by default on vista and newer. Apr 24, 2013 at 20:43
  • edit: using windows 7. I've never used either until today, I just thought batch file would be the easier of the two, I'm afraid my knowledge of powershell is even smaller than my batch file knowledge
    – R. Bean
    Apr 24, 2013 at 20:44
  • Thank you Scott, yes, that better reflects what I want to do
    – R. Bean
    Apr 24, 2013 at 20:53
  • +1, for a "novice" you did a really good job .... :)
    – Endoro
    Apr 25, 2013 at 5:24
  • Thanks for all your help everyone, I came here looking for one solution and you gave me two brilliant ones. You guys rock, Edit: If I could set both as the accepted answer I would, they both work perfectly
    – R. Bean
    Apr 25, 2013 at 13:35

2 Answers 2

2

Try this (set folder names and number of files to copy):

@echo off&setlocal enabledelayedexpansion
set "musicroot=test"
set "playfolder=output"
set /a filecount=20

pushd "%musicroot%"
for /r %%i in (*.mp3) do set /a files+=1& set "$!files!=%%~i"
popd
pushd "%playfolder%"
:randomloop
set /a rd=%random%%%files+1
set "mp3=!$%rd%!"
if not defined mp3 goto :randomloop
set "$%rd%="
for %%i in ("%mp3%") do if exist "%%~nxi" echo "%%~nxi" already exist in %playfolder%.& goto:randomloop
copy "%mp3%"
set /a filecount-=1
if %filecount% gtr 0 goto:randomloop
popd
1
  • That's brilliant, exactly what I wanted, thank you very very much.
    – R. Bean
    Apr 25, 2013 at 13:25
1

Here is a powershell solution

#edit this for your settings
$sourceFolder = 'E:\test'
$destFolder = 'E:\Test2'
$filesToCopy = 100
$searchFilter = '*.mp3'



function Copy-RandomFiles
{
param (
    [Parameter(Mandatory=$true, Position=0)]
    [string]$SourceDirectory,

    [Parameter(Mandatory=$true, Position=1)]
    [string]$DestinationDirectory,

    [int]$FilesToCopy = 100,

    [string]$SearchFilter = '*.*'
    )

    $rand = New-Object System.Random

    $files = [System.IO.Directory]::GetFiles($SourceDirectory, $SearchFilter, [System.IO.SearchOption]::AllDirectories)

    $usedIndexes = @{}
    $filteredList = New-Object System.Collections.ArrayList

    #build list of random indexes
    for([int]$i = 0; ($i -lt $FilesToCopy) -and ($i -lt $files.Length); $i++)
    {
        $index = $rand.Next(0, $files.Length)
        #loop till we find an available index
        while($usedIndexes.ContainsKey($index))
        {
            $index = $rand.Next(0, $files.Length)
        }

        $usedIndexes.Add($index, $null)
        $dump = $filteredList.Add($files[$index]) #dump is so it does not display a count
    }

    if($filteredList.Count -gt 0)
    {
        Copy-Item -Path $filteredList.ToArray() -Destination $DestinationDirectory
    }

    $count = $filteredList.Count

    Write-Host "$count file(s) copied"
}

Get-ChildItem $destFolder | Remove-Item
Copy-RandomFiles $sourceFolder $destFolder -FilesToCopy $filesToCopy -SearchFilter $searchFilter

Write-Host "Press any key to continue . . ."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

Save that as a text file on your hard drive somewhere with the .ps1 extension. Then create a shortcut link on your desktop with this as the path

%windir%\system32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Unrestricted -file C:\Path\To\CopyFileScript.ps1

This will delete everything in the $destFolder folder and copy $filesToCopy files from $sourceFolder and its subfolders using $searchFilter as a filter

2
  • I did a big re-write to the code if you have copied it already. Apr 24, 2013 at 23:12
  • Thank you so much, this is awesome stuff Scott. You're the man.
    – R. Bean
    Apr 25, 2013 at 13:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .