익명 03:27

How to sort only a sub-set of files in a directory in Windows Batch?

How to sort only a sub-set of files in a directory in Windows Batch?

I've written a script that lets me specify a range of files in a directory, say 10-20, or just the first ten, or the last ten, etc, and then the script feeds just those files to my chosen image viewer, Irfanview. I included options to sort the files alphabetically, or chronologically, and either in reverse order, as well as a thumbnail option.

Here is a vastly stripped down version. The full script has more options, more intuitive options, error handling, etc. It's also much more convoluted and harder to follow. This should be enough to illustrate what I want to do. If it helps, you can delete the Irfanview command, and just treat it as a script to create a list of the chosen files.

@echo off

set Pattern=%~1
set Start=%2
set End=%3
set Counter=1

for %%F in (%Pattern%) do set FilePath=%%~dpF

for /f "delims=" %%F in ('dir /b /on "%Pattern%"') do (set Filename=%%F
call :Process)

i_view32.exe /filelist=C:\Temp\FileList.txt
del C:\Temp\FileList.txt
goto:eof

:Process
if %Counter% geq %Start% (if %Counter% leq %End% echo "%FilePath%\%Filename%">>C:\Temp\FileList.txt )
set /a Counter=Counter+1
exit /b

Example usage:

iview.bat F:\Pics\\*.jpg 10 20

Would sort the list of jpegs in F:\Pics\ by name, and then display files 10-20.

I would like to create an option to also sort the chosen files by date.

Now I know someone is going to suggest changing the DIR command to DIR /b /od, but that won't do what I want. That would change the sort order for the entire directory, changing what files qualify as 10-20. I want to be able to display files 10-20 according to their alphabetical positions, and then sort just those files by date. In effect, a double-sort.

The most practical way I can think to do this is to also write each file's date/time to the text file in front of the filename, sort the file, which will use the date/time to order the lines, then read it back in one line at a time, discarding the date/time, writing the filenames out to a new file, and deleting the original. Then feed that new file to Irfanview.

I'm wondering if there isn't a more elegant way to do this though.

BTW, I want to use Batch, because it's the most compatible across different versions of Windows. It's also the only scripting language that I (mostly) know. I recently looked at Free BASIC thinking it would mostly be familiar to me. Unfortunately, it looks almost completely alien, and nothing like the BASIC that I know.



Top Answer/Comment:

Move to PowerShell; comes with Windows since Vista.
It looks intimidating at first, but it really isn't.
Anyway, you can integrate a line of PowerShell directly into your script that should do the job.
Unlike Batch, you will probably be able to follow what happens just by looking at the PowerShell code.
Note that I've added setlocal to the script. This avoids setting environment variables that persist in the shell when the script finishes.
I've also set a variable containing the target path.

@echo off
setlocal

set Pattern=%~1
set Start=%2
set End=%3
set FileList=C:\Temp\FileList.txt

REM This line will create the file list based on the range specified:
powershell.exe -Command "Get-ChildItem -File -Path '%Pattern%' | Sort-Object -Property Name | Select-Object -Skip (%Start% - 1) -First (%End% - %Start% + 1) | Sort-Object -Property Date | Select-Object -ExpandProperty FullName | Set-Content -Path '%FileList%'"

type "%FileList%"
REM i_view32.exe /filelist="%FileList%"

del "%FileList%"
  • Get-ChildItem is the PowerShell version of dir. -File will tell it to not return directories.
  • The file items will then be passed to Sort-Item, which will sort them by their Name property (which contains the file name only, no path).
  • The sorted objects will be passed further on to Select-Object, which will only return the objects inside the specified range.
  • The selected range will again be passed to Sort-Object, which will this time sort by their Date property.
  • This range will now be passed again through Select-Object, which will now with the ExpandProperty parameter return only the string values of the file objects' FullName property, which contains the file name including the path.
  • These strings will finally be passed to Set-Content, which will write them to the target file.
상단 광고의 [X] 버튼을 누르면 내용이 보입니다