Je travaille avec une grande collection de fichiers principalement textuels subdivisés par séries, les reproduisant périodiquement à partir d'un dépôt en amont et les reconditionnant à l'aide d'un shell script à partir d'une organisation de sources légèrement chaotique vers des formes plus ordonnées et compactes. Les sources sont rassemblées dans des répertoires de fichiers pour chaque série, allant d'une poignée à des centaines par série, avec une convention de nommage semi-ordonnée et orientée vers l'humain datant des années 90 avec ce modèle général :
nom de la série multi-mots[-$subsetnumber]-$docnumber[.{txt,html,pdf}]
Une série peut avoir ou non des sous-ensembles, les sous-ensembles peuvent être numérotés avec des chiffres romains ou arabes, une série peut commencer avec des documents numérotés dans aucun sous-ensemble et obtenir plus tard un sous-ensemble étiqueté "II" ou "2", et ainsi de suite. Ces noms fonctionnent bien pour les personnes qui les utilisent à partir du Finder, qui, dans la plupart des cas, les ordonne de manière humaine et détecte que le nom-II-1 vient après le nom-6 et que le nom-2 ne vient pas après le nom-19. Comme mon reconditionnement consiste à assembler la dernière version de chaque série dans des fichiers uniques dans leur ordre rationnel, j'utilise un simple bout d'AppleScript qui utilise le Finder pour trier les noms des éléments dans un répertoire donné. Cela donne des résultats corrects, mais c'est spectaculairement inefficace pour des raisons que je ne comprends pas. L'AppleScript est le suivant :
on run argv
set op to ""
set upath to POSIX file argv as string
tell application "Finder"
set foo to every item of folder upath
set foo to sort foo by name
repeat with curfile in foo
set thisname to the name of curfile
set op to op & " " & thisname as string
end repeat
end tell
return op
end run
(Et non, je ne me souviens pas de la raison pour laquelle j'ai procédé ainsi. Je l'ai écrit vers 2008 et je déteste surtout AppleScript...) Ceci est compilé dans un script nommé "flist.scpt" et exécuté depuis mon shell script avec "osascript flist.scpt /path/to/series/folder/". Le résultat de l'exécution de ce script avec un répertoire contenant 26 fichiers est de faire tourner le processeur pendant plus de 2 minutes. À titre de comparaison, "ls" donne des résultats triés lexicalement sur la même machine (un iMac G5 fonctionnant sous Leopard... ne riez pas, c'est une machine utilitaire) en 0,008 seconde. avec le script en arrière-plan dans le même répertoire.
Je cherche à me débarrasser complètement de cet AppleScript, mais je n'ai pas trouvé de moyen de reproduire facilement la logique de tri du Finder, c'est-à-dire en définissant une locale ou en donnant des arguments complexes à 'sort' qui ordonneront les noms correctement. Ma solution de repli, si je ne trouve pas quelque chose d'original, sera de reproduire moi-même la logique du Finder dans un mélange diabolique de sort, sed, awk et shell, mais j'aimerais vraiment éviter cela dans la mesure du possible. S'il y a quelque chose de bizarre dans mon AppleScript qui est à l'origine des performances horribles, le corriger serait presque aussi bien qu'une incantation magique à 'ls' pour qu'il trie comme le Finder.
MISE À JOUR : RÉSOLU ! J'ai d'abord essayé le module Perl Sort::Naturally, mais il triait les noms des sous-ensembles étiquetés avant les membres implicites du sous-ensemble "I", ce qui n'était pas ce que je voulais. Je me suis donc lancé dans l'écriture de mon premier script Ruby, après avoir modifié la configuration Ruby de Leopard pour que 'gem' fonctionne dans le monde moderne et installé la gem naturalsort. Le script de remplacement en Ruby (appelé avec un nom de répertoire comme argument) est :
#! /usr/bin/env ruby -rubygems -KU
# Largely cargo-culted from stackexchange response.
# I dunno what exactly the shebang line opts to ruby do. Probably pwn me.
# My first Ruby script ever. Don't laugh too hard.
require 'natural_sort' # gem install naturalsort
dname = ARGV[0]
input = Dir.entries(dname)
puts NaturalSort.naturalsort(input)
Les différences mineures dans la sortie sont que ceci inclut les entrées . et .. et délimite les entrées par ligne plutôt que par des espaces, mais comme ceci est appelé depuis un shell script qui filtre déjà certains noms spéciaux, ces différences sont triviales à gérer.