Wörter in Dateinamen mit sort alphabetisieren?

8

Beim Lesen von Tutorials zum Batch-Umbenennen von Dateien in Bash und beim Verwenden des sortBefehls zum Sortieren von Dateiinhalten konnte ich nicht herausfinden, wie beide kombiniert werden können.

Ich habe ein Verzeichnis, dessen Inhalt nach Tags im Dateinamen sortiert ist, ähnlich wie das Programm TagSpaces die Dinge handhabt. Ich füge alle denkbaren Tags am Ende des Dateinamens hinzu, wenn ich sie erstelle oder herunterlade. Hier ist ein Beispiel:

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

Jetzt möchte ich alle diese Dateien durchgehen und sie umbenennen, damit die Tags alphabetisch sortiert sind, ohne dass dies Auswirkungen auf die Tags vor oder nach den Tags hat (z. B. den Titel oder die Dateierweiterung eines Bildes). So würde das Obige werden:

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

Wie schaffe ich das? Ich kann nicht einmal herausfinden, wie ich den Namen einer Datei und nicht ihren Inhalt an einen Befehl wie übergeben soll sort, zu dessen Ausgabe ich dann vielleicht weiterleiten könnte mv.

ArdentCertes
quelle
Keine Antwort auf Ihre Frage, aber Sie sollten eine Antwort zu TagSpaces unter Hinzufügen von Tags zu Dateien (PDFs) veröffentlichen und über die Befehlszeile oder das Skript verarbeiten - dies scheint auf den ersten Blick für diese Frage sehr relevant zu sein.
Cas

Antworten:

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

Testen:

##### 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
quelle
3

Wenn Sie Perl-basiert haben rename( prenameauf einigen Systemen), können Sie die Tags mit Perl teilen und sortieren. Zum Beispiel gegeben

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

dann (mit einigen hässlichen Auseinandersetzungen, um das .jpgSuffix zu entfernen und zu ersetzen )

$ 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

Überprüfung

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

Wahrscheinlich viel Raum für Verbesserungen - aber ich hoffe, es gibt Ihnen eine Idee.

Steeldriver
quelle
3

Mit zsh:

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

(Entfernen Sie den -n(Trockenlauf), wenn Sie zufrieden sind).

  • [^#]#: 0 oder mehr Nicht-# -Zeichen ( #wie *in regulären Ausdrücken)
  • s: : auf Raum teilen
  • o: order (sort)
  • j: :: mit dem Raum verbinden.

Also teilen wir den Teil zwischen dem ersten #(eingeschlossen) und dem letzten .(ausgeschlossen) im Raum auf und sortieren die resultierende Liste, die wir mit dem Raum verbinden.

Rekursiv:

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

Um Leerzeichen in Tag-Namen zuzulassen, können wir #nachfolgende Leerzeichen aufteilen und kürzen, sortieren und verbinden #mit:

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

Fügen Sie ein (#qD)Glob-Qualifikationsmerkmal hinzu, wenn Sie auch versteckte Dateien ( Dot-Dateien) oder Dateien in versteckten Verzeichnissen verarbeiten möchten.

Stéphane Chazelas
quelle
2

Gute Frage!

Hier ist mein einfaches bashSkript dafür:

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

Erläuterung:

  • In afile=( ${file#*)} );: Wir konvertieren den String in ein Array. In diesem Zustand führt die Shell eine Wortteilung mit Leerzeichen durch, es sei denn, Sie zitieren die Zeichenfolge.

    In ${file#*)}( Cut-up-to-First-Präfix ): Wir entfernen alles vom Anfang der Zeichenfolge bis zur ersten )Verwendung, shell parameter expansionda dies unter #wallpaper #4k #googleimages.jpgBerücksichtigung derfile="Sunrise (2) #wallpaper #4k #googleimages.jpg"

  • In ${file%%#*}( Cut-up-to-Last-Suffix ); Abisolierstart vom Ende bis zum Betteln der Saite bis zuletzt #gesehen. dies wird resultierenSunrise (2)

  • In ${afile[@]%%.*}( Cut-up-to-Last-Suffix ): Wie oben, beginnt das Strippen vom Ende bis zum Betteln des Strings (hier in jedem indizierten Array) bis zum letzten .Mal. Dies wird dazu führen #wallpaper #4k #googleimages, wir könnten auch ${afile[@]%.*}besser gebrauchen !

  • In printf "%s\n" "${afile[@]%%.*}": Wir drucken die Array-Elemente mit Zeilenumbrüchen ( [@]wird für indizierte Arrays verwendet) (warum mit Zeilenumbrüchen? Weil wir sie sortieren und die Elemente in Zeilenumbrüche aufteilen sollten).

  • In $(sort<(printf "%s\n" "${afile[@]%%.*}")): Wir sortieren die Elemente (oder Tags).

  • In $(echo $(sort<(printf "%s\n" "${afile[@]%%.*}"))): wie oben, aber wir haben einen zusätzlichen echoBefehl verwendet, um die sortierten Elemente in einer linearen zu sammeln.

    möglich gleich auch bei Verwendung von double xargslike ... |xargs -n1| sort | xargs.
    Bitte sehen Sie das folgende Beispiel, um diesen Schritt besser zu verstehen:

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

Schließlich wird am Ende der mvBefehl den $filein den geänderten Namen umbenannten Namen umbenennen .

Ps: vor dem entfernen, echo mv ...um den mvTrockenlauf zu beenden und das eigentliche Umbenennen durchzuführen.

αғsнιη
quelle
1

Dies scheint ein bisschen zu kompliziert für Bash, um ehrlich zu sein. Es ist nicht unmöglich, aber meiner Meinung nach ist es weitaus besser, eine Sprache zu verwenden, die für "echte" Programmierung gemacht ist. Eine Bash-Lösung ist wahrscheinlich nicht zu verwalten. (Ich versuche nicht, die Nur-Bash-Lösung zu beleidigen, aber ich finde die Umbenennungsmagie eigentlich ziemlich erstaunlich.)

Das heißt, hier ist eine Lösung mit Ruby. Sie können es in eine Datei schreiben und die Datei dann einfach aus Ihrer Shell heraus ausführen, vorausgesetzt, Sie haben Ruby installiert.

#!/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

Um das Skript auszuführen, platzieren Sie es einfach in dem Verzeichnis, in dem sich Ihre Bilder befinden. Diese Lösung sollte ziemlich widerstandsfähig gegenüber albernen Bildnamen und Tags sein, C#die keine Probleme verursachen. Stellen Sie jedoch sicher, dass Sie ein Backup erstellen, bevor Sie das Skript ausführen. Bewegungsoperationen können genauso zerstörerisch sein wie rm.

PawkyPenguin
quelle