Alphabétiser les mots dans les noms de fichiers en utilisant le tri?

8

Lors de la lecture de didacticiels sur les fichiers renommés par lots dans bash et en utilisant la sortcommande pour trier le contenu des fichiers, je n'ai pas été en mesure de comprendre comment combiner les deux.

J'ai un répertoire dont le contenu est trié à l'aide de balises dans le nom de fichier, similaire à la façon dont le programme TagSpaces gère les choses. J'ajoute toutes les balises auxquelles je peux penser à la fin du nom de fichier lorsque je le crée ou le télécharge. Voici un exemple:

Sunrise (2) #wallpaper #4k #googleimages.jpg

Maintenant, je veux parcourir tous ces fichiers et les renommer pour que les balises soient triées par ordre alphabétique, sans affecter quoi que ce soit avant ou après les balises (par exemple, le titre d'une image ou l'extension de fichier). Ainsi, ce qui précède deviendrait:

Sunrise (2) #4k #googleimages #wallpaper.jpg

Comment est-ce que j'accomplis ceci? Je ne peux même pas comprendre comment passer le nom d' un fichier , et non son contenu, à une commande comme sort, dont je pourrais peut-être ensuite diriger la sortie mv.

ArdentCertes
la source
pas une réponse à votre question, mais vous devez publier une réponse sur TagSpaces dans Ajout de balises aux fichiers (PDF) et le processus à partir de la ligne de commande ou du script - cela semble très pertinent à cette question à première vue.
cas

Réponses:

5
#!/bin/bash

for i in dir_for_files/*; do
    filename=${i%%#*}
    sorted_tags=$(grep -o "#[^ .]*" <<< "$i" | sort -n | tr '\n' ' ')
    ext=${i#*.}
    echo mv "$i" "${filename}${sorted_tags% }.$ext"
done

Essai:

##### Before sorting #####    
$ ls -1 dir_for_files
Note (3) #textfile #notes #important.txt
Sunrise (2) #wallpaper #4k #googleimages.jpg
Sunset (2) #wallpaper #2k #images.jpg

$ ./sort_tags.sh

##### After sorting #####
$ ls -1 dir_for_files
Note (3) #important #notes #textfile.txt
Sunrise (2) #4k #googleimages #wallpaper.jpg
Sunset (2) #2k #images #wallpaper.jpg
MiniMax
la source
3

Si vous avez basé sur perl rename( prenamesur certains systèmes), vous pouvez faire un split + trier les balises en utilisant perl. Par exemple, étant donné

$ ls *.jpg
Sunrise (2) #wallpaper #4k #googleimages.jpg

puis (avec quelques vilaines querelles pour supprimer et remplacer le .jpgsuffixe)

$ rename -v 'my @F = split / #/, substr($_,0,-4); $_ = (join " #", shift @F, sort @F) . ".jpg"' *.jpg
Sunrise (2) #wallpaper #4k #googleimages.jpg renamed as Sunrise (2) #4k #googleimages #wallpaper.jpg

Vérification

$ ls *.jpg
Sunrise (2) #4k #googleimages #wallpaper.jpg

Probablement beaucoup de place pour l'amélioration - mais j'espère que cela vous donnera une idée.

tournevis
la source
3

Avec zsh:

autoload zmv # best in ~/.zshrc
zmv -n '([^#]#)(\#*)(.*)' '$1${(j: :)${(os: :)2}}$3'

(retirer le -n(essai à sec) si heureux).

  • [^#]#: 0 ou plusieurs caractères non # ( #comme *dans les expressions rationnelles)
  • s: : divisé sur l'espace
  • o: ordre (trier)
  • j: :: rejoindre l'espace.

Donc, nous séparons la partie entre le premier #(inclus) et le dernier .(exclu) sur l'espace, trions la liste résultante que nous rejoignons avec l'espace.

Récursivement:

zmv -n '(**/)([^#]#)(\#*)(.*)' '$1$2${(j: :)${(os: :)3}}$4'

Pour autoriser les espaces dans les noms de balises, nous pouvons diviser #et découper les espaces de fin, trier et fusionner #avec:

zmv -n '([^#]#\#)(*)(.*)' '$1${(j: #:)${(os:#:)2}%% #}$3'

Ajoutez un (#qD)qualificatif glob si vous souhaitez également traiter des fichiers cachés ( Dfichiers ot) ou traiter des fichiers dans des répertoires cachés.

Stéphane Chazelas
la source
2

Bonne question!

Voici mon bashscript simple pour cela:

for file in *.jpg; do 
    afile=( ${file#*)} ); 
    echo mv "$file" "${file%%#*}$(echo $(sort<(printf "%s\n" "${afile[@]%%.*}"))).jpg";
done

Explication:

  • Dans afile=( ${file#*)} );: nous convertissons la chaîne en un tableau. Dans cet état, le shell effectue la séparation des mots avec des espaces, sauf si vous citez la chaîne.

    Dans ${file#*)}( cut-up-to-first-prefix ): nous supprimons tout depuis le début de la chaîne jusqu'à la première )vue, shell parameter expansioncar cela résultera de #wallpaper #4k #googleimages.jpglafile="Sunrise (2) #wallpaper #4k #googleimages.jpg"

  • In ${file%%#*}( découpage jusqu'au dernier suffixe ); le décapage commence de la fin à la mendicité de la ficelle jusqu'à la dernière #vue. cela se traduiraSunrise (2)

  • Dans ${afile[@]%%.*}( coupe-au-dernier-suffixe ): comme ci-dessus, la suppression commence de la fin au début de la chaîne (ici dans chaque tableau indexé) jusqu'à la dernière .fois. cela se traduira #wallpaper #4k #googleimages, nous pourrions également utiliser ${afile[@]%.*}mieux!

  • Dans printf "%s\n" "${afile[@]%%.*}": nous imprimons les éléments du tableau avec des retours à la ligne ( [@]utilisés pour les tableaux indexés), (pourquoi avec les retours à la ligne? Parce que nous allons les trier et nous devons diviser les éléments en retours à la ligne)

  • Dans $(sort<(printf "%s\n" "${afile[@]%%.*}")): nous trions les éléments (ou balises).

  • Dans $(echo $(sort<(printf "%s\n" "${afile[@]%%.*}"))): comme ci-dessus, mais nous avons utilisé une echocommande supplémentaire pour rassembler les éléments triés dans l'un linéaire.

    possible même également en utilisant le double xargscomme ... |xargs -n1| sort | xargs.
    Veuillez voir l'exemple ci-dessous pour mieux comprendre cette étape:

    echo -e "C\n4\nB" |sort
    4
    B
    C
    echo $(echo -e "C\n4\nB" |sort)
    4 B C

Enfin, à la fin, la mvcommande renomme le $fileau nom modifié devrait être.

Ps: supprimez echo mv ...devant le mvpour quitter le dry-run et effectuez un changement de nom.

αғsнιη
la source
1

Cela semble un peu trop compliqué pour que Bash soit honnête. Ce n'est pas impossible, mais à mon avis, il vaut mieux utiliser ici un langage conçu pour une "vraie" programmation. Une solution Bash sera probablement impossible à gérer. (N'essayant pas d'insulter la solution Bash uniquement, je pense que la magie du renommage est assez incroyable, en fait)

Cela dit, voici une solution avec Ruby. Vous pouvez l'écrire dans un fichier, puis exécuter simplement le fichier à partir de votre shell, étant donné que Ruby est installé.

#!/usr/bin/env ruby
Dir.glob('*.jpg').each do |filename|
    # `name` contains the name of the file, without the tags. `tags` is an array
    # of all tags of the file.
    name, *tags = filename.split(' #')
    # if there aren't any tags, just skip the file.
    if tags.empty?
        next
    end
    # remove the trailing '.jpg' and sort all the tags
    tags.last.gsub!(/\.jpg$/,'')
    tags.sort!
    tags = [name] + tags
    # finally, move the file to the correct location with sorted tags.
    File.rename filename, "#{tags.join(' #')}.jpg"
end

Pour exécuter le script, placez-le simplement dans le répertoire où se trouvent vos images. Cette solution devrait être assez résistante aux noms d'images idiotes et aux balises comme C#cela ne causera pas de problèmes. Cela dit, assurez-vous de faire une sauvegarde avant d'exécuter le script. Les opérations de mouvement peuvent être tout aussi destructrices qu'un rm.

PawkyPenguin
la source