J'essaie d'écrire un peu de rubis qui rechercherait récursivement un répertoire donné pour tous les annuaires d'enfants vides et les supprimer. P>
pensées? P>
Remarque: je voudrais une version de script si possible. Ceci est à la fois un besoin pratique et une chose pour m'aider à apprendre. P>
9 Réponses :
Pourquoi pas simplement utiliser Shell? P>
trouver. -Type D -empty -exec rmdir '{}' \; p> blockQuote>
fait exactement ce que vous voulez. p>
J'espérais une version de script Ruby pour saisir la saisie de fichiers. Je pourrais appeler ce qui précède avec 'sh
La commande de script serait exactement la même. Cependant, la poste ci-dessous a une réponse qui vous conviendra.
dans Ruby:
Dir['**/*'] \
.select { |d| File.directory? d } \
.select { |d| (Dir.entries(d) - %w[ . .. ]).empty? } \
.each { |d| Dir.rmdir d }
Pourriez-vous expliquer le "-" en ligne 3?
Je soustraire le tableau contenant les chaînes "". et ".." à partir du tableau des entrées d'annuaire, car chaque répertoire contient ces deux entrées spéciales.
Aussi, pourriez-vous expliquer ce que sont les "\" sont pour? continuation de la ligne? sont-ils nécessaires?
Ils sont la continuation de la ligne, oui. Ils ne sont pas nécessaires si vous mettez le point à la fin de la ligne précédente, mais je les aime au début pour préciser que cette ligne se poursuit de la précédente. (Bien que vraiment, je viens de se formater en tant que telle à des fins d'affichage. Je laisse généralement ces choses en une seule ligne, jusqu'à ~ 160 caractères. Certaines personnes me détestent, oui. Je pense qu'ils utilisent des tys.)
haha. Merci Kch tu m'as sauvé un peu de temps. J'ai eu tout le doco qui s'est arrêté, mais il manquait une partie de la plus grande image pour tout mettre ensemble.
Vous voyez, la façon dont j'ai écrit le code, si j'ai laissé tomber le \ s, Ruby pourrait interpréter la ligne comme une expression complète et que cela le ferait.
Vous devez supprimer dans l'ordre inverse, sinon vous ne supprimerez pas tous les répertoires vides.
Dir.glob('**/*').each do |dir|
begin
Dir.rmdir dir if File.directory?(dir)
# rescue # this can be dangereous unless used cautiously
rescue Errno::ENOTEMPTY
end
end
Sauver de toute exception Willy-Nilly n'est pas la meilleure idée du code de production réel.
Habituellement, je devrais être d'accord, mais c'est une sorte de situation limite. En tout cas, j'ai mis à jour la déclaration de sauvetage.
Oui, c'est une de ces choses qui vont aussi longtemps que vous savez ce que vous faites. Mais un googler frappe cette page pourrait être considéré comme un script rapide ou pour une bibliothèque qui aura un rôle majeur dans une application intensive de systèmes de fichiers. Ainsi, fondamentalement, N00BS Obtenez le code de sécurité par défaut et les personnes qui savent censeusement savoir ce qu'ils font le feront à leurs propres risques.
J'ai testé ce script sur OS X, mais si vous êtes sous Windows, vous devrez apporter des modifications.
Vous pouvez trouver les fichiers d'un répertoire, y compris des fichiers cachés, avec les entrées n ° DIR.
Ce code supprimera des annuaires qui deviennent vides une fois que vous avez supprimé des sous-répertoires. P>
def entries(dir)
Dir.entries(dir) - [".", ".."]
end
def recursively_delete_empty(dir)
subdirs = entries(dir).map { |f| File.join(dir, f) }.select { |f| File.directory? f }
subdirs.each do |subdir|
recursively_delete_empty subdir
end
if entries(dir).empty?
puts "deleting #{dir}"
Dir.rmdir dir
end
end
module MyExtensions
module FileUtils
# Gracefully delete dirs that are empty (or contain empty children).
def rmdir_empty(*dirs)
dirs.each do |dir|
begin
ndel = Dir.glob("#{dir}/**/", File::FNM_DOTMATCH).count do |d|
begin; Dir.rmdir d; rescue SystemCallError; end
end
end while ndel > 0
end
end
end
module ::FileUtils
extend FileUtils
end
end
Dir['/Users/path/Movies/incompleteAnime/foom/**/*']. \
select { |d| File.directory? d }. \
sort.reverse. \
each {|d| Dir.rmdir(d) if Dir.entries(d).size == 2}
just like the first example, but the first example doesn't seem to handle the recursive bit. The sort and reverse ensures we deal with the most nested directories first.I suppose sort.reverse could be written as sort {|a,b| b <=> a} for efficiency
Vous devez supprimer dans l'ordre inverse, sinon si vous avez un répertoire vide FOO avec une barre de sous-répertoire, vous supprimerez la barre, mais pas FOO.
Dir.glob(dir + "/**/*").select { |d|
File.directory?(d)
}.reverse_each { |d|
if ((Dir.entries(d) - %w[ . .. ]).empty?)
Dir.rmdir(d)
end
}
Regarder les exemples de KCH, DB. et Vishnu ci-dessus, j'ai mis en place un one-liner que je pense est une solution plus élégante: i utilise J'ai testé cela assez un peu sur Mac OS X et cela fonctionne bien, même avec des répertoires vides récursifs. P> P> '** /' code> au lieu de < Code> '/ ** / *' code> Pour le GLOB, qui ne renvoie que des annuaires, je n'ai donc pas à tester s'il s'agit d'un répertoire ultérieurement. J'utilise inverse_each code> au lieu de trier.reverse.each code> car il est plus court et supposé plus efficace, selon ce POST . Je préfère dir.entries (d) .Size == 2 code> à (dir.entries (D) -% w [. ..]). Vide? Code> parce que c'est un Peu plus facile de lire et de comprendre, bien que (dir.entries (d) -% w [. ..]). Vider? code> fonctionnerait probablement mieux si vous deviez exécuter votre script sur Windows. p>
Une compilation très élégante de solutions.
Nice refacteur mais je pense que mentionnant. et .. est plus intuitif que la taille == 2 Donc j'irais avec `dir ['lib / ** /']. Reverse_each {| D | Dir.RMDIR D Si DIR.Entries (D) .sort ==% w (..)} `
Oui, ce genre de monde est plus intuitif.
Nice approche, j'irais pour ce qui suit ces jours-ci: dir [* ** / ']. Reverse_each {| D | Dir.RMDIR (D) Si Dir.empty? (D)} code> ou même plus court DIR ['** /']. Reverse_each {Dir.RMDIR (_1) Si Dir.empty? (_ 1) } code>. Cependant, vous devez noter que cette solution construit une matrice de tous les répertoires en mémoire. Vous ne devez donc pas l'utiliser, mais au cas où vous sachiez que le nombre de répertoires (tous, pas seulement les vides) est limité.
Pour une solution pure Shell, j'ai trouvé ce très utile mais si vous avez installé GNU-Trouvez (pas encore universel) ... p> find . -depth -type d -print0 |
xargs -0n1 sh -c '[ "`cd "$0"; echo .* * ?`" = ". .. * ?" ] &&
echo "rmdir $0";'
C'est vraiment cool. Je cherchais à l'origine une solution de rubis, mais c'est très pratique de le faire dans Bash si Ruby n'est pas installé sur un système. Merci!
Première pensée: Système "Trouver. -Type D | Xargs RMDIR -P 2> / dev / null"
Juste une note, je ne veux pas faire cette opération en un coup de la ligne de commande. Sa va être dans un script rubis. Qu'est-ce que vous avez ci-dessus est une version cmd ligne non?
Eh bien, c'est une commande shell, oui, mais invoquée à partir de rubis en utilisant
kernel.system code>;)