Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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.

share|improve this question
    
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. –  Scott Chamberlain Apr 24 '13 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 '13 at 20:44
    
Thank you Scott, yes, that better reflects what I want to do –  R. Bean Apr 24 '13 at 20:53
    
+1, for a "novice" you did a really good job .... :) –  Endoro Apr 25 '13 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 '13 at 13:35

2 Answers 2

up vote 1 down vote accepted

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
share|improve this answer
    
That's brilliant, exactly what I wanted, thank you very very much. –  R. Bean Apr 25 '13 at 13:25

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

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

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.