Die Frage wurde aufgrund der Erkenntnisse aus den ersten beiden Antworten und Kommentaren, die mir beim ersten Fragen nicht bekannt waren, komplett neu geschrieben.
Nach einem Fotoshooting komme ich mit Dateien nach Hause, die aussehen _DSC1234.NEF
. NEF
ist das Rohdateiformat für die Kamera von Nikon, sodass EXIF
Daten in den Dateien vorhanden sind.
Ich möchte sie automatisch in drei Teile umbenennen:
- Erstellungsdatum im Format
YYYYMMDD
- Name des Schusses
- Anzahl der Bilder
Der endgültige Dateiname sollte also so aussehen
20140707_NameOfShoot_0001.NEF
Es gibt einige Probleme:
Anzeige 1. Erstellungsdatum
Manchmal kann ich die Dateien nur einige Tage nach der Aufnahme kopieren und umbenennen. Das Datum sollte also das Aufnahmedatum und nicht das Kopierdatum widerspiegeln. mtime
scheint hier die beste Wahl zu sein oder wenn möglich Erstellungsdatum von EXIF
.
Anzeige 2: Name des Shoots Dies wäre idealerweise eine Variable, die ich beim Aufrufen des Skripts als Parameter festlegen könnte.
ad 3. Anzahl der Bilder
Dies sollte das Alter des Bildes widerspiegeln, wobei das älteste die niedrigste Anzahl hat. Das Problem ist, dass Kameras die Nummerierung normalerweise 0000
nach dem Treffer neu starten 9999
. So 9995-9999
kann möglicherweise älter als 0000-0004
. Ich suche nach einer Lösung, die das Alter der Datei widerspiegelt und in diesem speziellen Fall umbenennen würde
- _DSC0000.NEF -> 20140707_FOO_0004.NEF
- _DSC0001.NEF -> 20140707_FOO_0005.NEF
- _DSC0002.NEF -> 20140707_FOO_0006.NEF
- ...
- _DSC9997.NEF -> 20140707_FOO_0001.NEF
- _DSC9998.NEF -> 20140707_FOO_0002.NEF
- _DSC9999.NEF -> 20140707_FOO_0003.NEF
Auch hier scheint entweder mtime
oder wenn möglich das Erstellungsdatum von EXIF
richtig zu sein.
Von hier aus habe ich eine funktionierende Lösung, die alle .NEF-Dateien in einem Ordner nach Datum umbenennt:
find -name '*.NEF' |
gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.NEF\n", $0, a++ }' |
bash
Das Änderungsdatum der Hardcodedatei und der Shootname funktionieren gut, aber es wäre großartig, wenn es automatisiert werden könnte.
Für die Zeitmarke I Artikel finden auf strftime()
, mktime()
, systime()
aber ich verstehe nicht, wie sie verwenden , um Dateiänderungsdatum zurück. Ich habe auch versucht, die Gawk-Zeile hinzuzufügen DATE=$(date +"%Y%m%d")
und zu ergänzen $DATE
, was zum Löschen aller Dateien im aktuellen Ordner führt (und wahrscheinlich sowieso Systime ist und die Zeit nicht ändert).
Für die Variable habe ich versucht
gawk 'BEGIN{ a=1 }{ printf "mv %s $1_%04d.NEF\n", $0, a++ }' |
und rufen Sie das Skript mit auf ./rename FOO
, aber FOO wird beim Umbenennen ignoriert.
stat -c %W -- *
in meinem Home-Verzeichnis versucht und nur ein paar Nullen zurückgegeben. Auf derman find
Seite von GNU wird auch dokumentiert, dass-printf
strftime
Sequenzen für%A
Zugriff, Statusänderung%C
und Änderung%T
verarbeitet werden können, jedoch nichts über die Erstellung oder Geburt von Dateien. Das beweist zwar nicht unbedingt, dass dies nicht möglich ist, aber ich denke, es ist ein guter Indikator dafür, dass es sich nicht um eine allgemein verfügbare Funktion handelt.Antworten:
Die meisten Unices verfolgen das Erstellungsdatum einer Datei nicht¹. "Erstellungsdatum" ist ohnehin schlecht definiert (erstellt das Kopieren einer Datei eine neue Datei?). Sie können die Änderungszeit der Datei verwenden, die nach vernünftiger Interpretation das Datum ist, an dem die neueste Version der Daten erstellt wurde. Wenn Sie Kopien der Datei erstellen, achten Sie darauf, die Änderungszeit beizubehalten (z. B.
cp -p
odercp -a
wenn Sie dencp
Befehl verwenden, nicht nacktcp
).Einige Dateiformate enthalten ein Feld in der Datei, in das die Erstelleranwendung ein Erstellungsdatum eingibt. Dies ist häufig bei Fotos der Fall, bei denen die Kamera einige Exif- Daten in JPEG- oder TIFF-Bildern ausfüllt , einschließlich der Erstellungszeit. Das NEF-Bildformat von Nikon umschließt TIFF und unterstützt auch Exif.
Es gibt vorgefertigte Tools zum Umbenennen von Bilddateien mit Exif-Daten, um das Erstellungsdatum in den Dateinamen aufzunehmen. Das Umbenennen von Bildern, um das Erstellungsdatum in den Namen aufzunehmen, zeigt zwei Lösungen: exiftool und exiv2 .
Ich glaube nicht, dass Sie mit einem der beiden Tools einen Zähler in den Dateinamen aufnehmen können. Sie können Ihre Umbenennung in zwei Durchgängen vornehmen: Fügen Sie zuerst das Datum (mit einer möglichst hohen Auflösung, um die Reihenfolge beizubehalten) in den Dateinamen ein, nummerieren Sie dann die Dateien entsprechend diesem Datumsteil (und geben Sie die Uhrzeit ein). Da moderne DSLRs Bildbursts auslösen können (Nikons D4s schießt mit 11 Bildern pro Sekunde), ist es ratsam, auch in der ersten Phase den ursprünglichen Dateinamen beizubehalten, da dies sonst möglicherweise zu mehreren Dateien mit demselben Dateinamen führen würde.
${x%-*}
Entfernt den Teil nach dem-
Zeichen. Die Zählervariablei
zählt ab 10000 und wird verwendet, wobei die führende1
Ziffer entfernt wird. Dies ist ein Trick, um die führenden Nullen zu erhalten, sodass alle Zählerwerte dieselbe Zahl haben.Das Umbenennen von Dateien durch Inkrementieren einer Zahl innerhalb des Dateinamens bietet andere Lösungen zum Umbenennen einer Reihe von Dateien, um einen Zähler einzuschließen.
Wenn Sie den Zeitstempel einer Datei anstelle von Exif-Daten verwenden möchten, lesen Sie Umbenennen einer Reihe von Dateien mit dem Datumsänderungsstempel am Ende des Dateinamens.
Generieren Sie im Allgemeinen keinen Shell-Code und leiten Sie ihn dann in eine Shell weiter. Es ist unnötig verwickelt. Zum Beispiel anstelle von
Du kannst schreiben
Beachten Sie, dass beide Versionen zu katastrophalen Ergebnissen führen kann , wenn ein Dateiname Shell Sonderzeichen (wie Leerzeichen enthalten
'
,$
,`
, etc.) , da der Dateiname wird als Shell - Code interpretiert. Es gibt Möglichkeiten, dies in robusten Code umzuwandeln, aber dies ist nicht der einfachste Ansatz, daher werde ich diesen Ansatz nicht weiterverfolgen.¹ Beachten Sie, dass es etwas gibt, das als "ctime" bezeichnet wird, aber
c
nicht zur Erstellung , sondern zur Änderung . Die ctime ändert sich jedes Mal, wenn sich etwas an der Datei ändert, entweder in ihrem Inhalt oder in ihren Metadaten (Name, Berechtigungen, ...). Die ctime ist so ziemlich das Gegenteil einer Schöpfungszeit.quelle
NameOfShoot
das wäre vom ursprünglichen Dateinamen. In Bezug auf die Daten bin ich mit dem NEF-Format nicht vertraut. Enthält es einen Erstellungsstempel im Dateiformat? Beispielsweise können JPEG-Bilder das Datum enthalten, an dem das Bild aufgenommen wurde (es ist Teil der EXIF-Daten). Viele (aber nicht alle) Kameras tun dies. Möchten Sie in Bezug auf die Sortierung, dass die älteste Datei 0001, die nächstälteste 0002 usw. ist?_DSC1234.NEF
, wird das auch zur Originalfrage hinzufügen.Der obige Befehl sollte das tun, was Sie brauchen. Es ist vielleicht allgemeiner als Sie es gewünscht haben - aber bitte sehen Sie am Ende dieser Antwort ein spezifischeres Beispiel.
Es funktioniert, indem
*
alle Dateien im aktuellen Verzeichnis globalisiert und ihre Änderungszeiten ausgedruckt werden. Für nur Dateien im aktuellen Verzeichnis, die das Suffix enthalten.NEF
, möchten Sie den*
Globstar an den Enden der Zeilen 1 und 5 in ändern*.NEF
. Es werden einige Shell-Variablen und Anführungszeichen an das Ende angehängt - deren Namen nur am anderen Ende der Pipeline in dersh
Subshell vorhanden sind.Da wir die Dateinamen nur anhand ihrer Glob-Reihenfolge oder der
${1}
Shell-Typparameter angeben, funktioniert dies auch mit jedem Dateinamen - unabhängig davon, welche seltsamen Zeichen darin enthalten sind.Im
echo
Moment enthält der Befehl ein - es ist nerfed. Laufen ist im Wesentlichen ein No-Op - es zeigt Ihnen nur, was es tun möchte. Hier ist die Ausgabe aus meinem Home-Verzeichnis, bevor es an Folgendes weitergeleitet wirdsh
:Hier ist es nach
sh
:Möglicherweise stellen Sie fest, dass in meiner Ausgabe einige Bilddateien angezeigt werden, die bereits nach ihrer Erstellungszeit benannt wurden, deren neu zugewiesener Name jedoch nicht übereinstimmt. Dies ist keine Auswirkung von
sort
- was wie vorgeschrieben funktioniert -, sondern dass diese Dateien zuletzt an diesem Datum eine Statusänderung hatten. Wie Sie in den Kommentaren zu dieser Frage angegeben haben,ctime
handelt es sich jedoch um die Eigenschaft, nach der Sie suchen. Dies ist die hier angebotene Eigenschaft für Sortierung und Name. Hier ist jedochstat
die Ausgabe mit angehängten Dateinamen:Die obige Ausgabe soll mir auch helfen, zu demonstrieren, was die gesamte Pipeline tut.
So
stat --printf='}" "%z_${SN}_${LINENO}"\n'
druckt Linien , die wie folgt aussehen:}" "YYYY-MM-DD HH:MM:SS.NS -TZ_${SN}_${LINENO}"
... wo
YMDHMS.NS -TZ
sind die verschiedenenstrftime
Komponenten , die sie repräsentieren fürctime
. Das Ausgabeformat ist identisch für%w
- Zeitpunkt der Geburt der Datei -%x
- Zeitpunkt des letzten Zugriffs - oder%y
- Zeitpunkt der letzten Änderung. Wenn Sie also eines dieser Elemente%z
in der obigen Anweisung ersetzen, wird es stattdessen auf ihre Werte erweitert. Wie wir bereits in den Kommentaren besprochen haben, ist die%w
Geburtszeit der Datei kein verlässliches Attribut, und wenn sie nicht unterstützt wird, wird sie nur auf erweitert0
.Dies geschieht für jede Datei, in der sich die Shell-Globs befinden,
*
oder für die von Ihnen bereitgestellten Shell-Globs - beispielsweise*.NEF
nur für Dateien im aktuellen Verzeichnis mit dem.NEF
Suffix.Diese Liste wird übergeben, an
nl
welche Zahlen jede Zeile um 1 erhöht wird. Ihre-n
Zeilennummern sind linksbündigln
und nicht mit einer Mindest--w
ID von 1 und nur einer''
Nullzeichenfolge-s
aufgefüllt, um sie vom Inhalt der Zeile zu trennen. Es gibt aus:I}" "YYYY-MM-DD HH:MM:SS.NS -TZ_${SN}_${LINENO}"
... wo
I
ist die Nummer jeder Zeile.sort
sortiert seine Eingabe vom-k2,3
zweiten Feld bis zum dritten - oder weiterYYYY-MM-DD HH:MM:SS.NS
. Da zu diesem Zeitpunkt die einzige eindeutige Qualität einer Zeile entwederI
das Datum oder das Datum ist undI
übersprungen wird, müssen keine genaueren Angaben gemacht werden. Dies betrifft auch den Kommentar, den Sie zu Dateien abgegeben haben, die nach Nummer und nicht nach Datum benannt sind. Ich sollte das getan haben ,sort
bevorsed
in erster Linie , aber es fiel mir nicht auf Minuten zu sortieren und Sekunden und dergleichen.Meine Testbasis dafür wurde wie folgt generiert:
Wenn ich
sort
nachsed
- wie ich vor diesem bearbeiten tue - dann würde diese Dateien umbenennen , so dass9
ich${DATE}.SHOOTNAME.9
da jede DateiYMD
Felder sind identisch undsort
würden nicht ihre Linie Ordnung beeinflussen. Bei dieser Einstellung ist dieser Befehl jedochsort
spezifisch für die Nanosekunde und wird daher9
in${DATE}.SHOOTNAME.1
und umgekehrt für umbenannt1
. Danke, @Seul, dass du mich darauf aufmerksam gemacht hast.sed
Entfernt dann die erste Zeichenfolge, die aussieht,<space><any char><any char>:<colon>
und alle nachfolgenden Zeichen, die^
kein_
Unterstrich sind. An diesem Punkt sieht die Linie also so aus:I}" "YYYY-MM-DD_${SN}_${LINENO}"
... als nächstes werden alle
-
Striche entfernt. Und schließlich wird esecho mv "${
am^
Kopf jeder Zeile eingefügt, also sieht es so aus:sh
Ell mit der$SN
deklarierten Umgebungsvariablen aufgerufen - hier ist ihr WertSHOOTNAME
. POSIX gibt an, dass die Shell die Variable$LINENO
für jede Zeile, die sie einliest, erhöht. Daher sollte der Wert im Dateinamen für jede Zeile, die wir eingeben, auf eins mehr als die letzte erweitert werden. Wenn dies - wie aus Ihren Kommentaren hervorgeht - aus irgendeinem Grund nicht auftritt, wird ein vollständig gültiger Ersatz$((i=i+1))
wie zuerststat
in Zeile 1 der Pipeline gedruckt und wie ich in einem speziellen Beispiel unten angegeben habe.Die Shell wird auch mit ihren Positionsparametern aufgerufen, die auf unseren Glob eingestellt sind - hier der
*
Globstar für alle Dateien im aktuellen Verzeichnis. Wie bereits erwähnt, würde*.NEF
in dieser und in der ersten Zeile nur Dateien im aktuellen Verzeichnis mit dem Dateinamensuffix von bearbeitet.NEF
.Solange der Globus mit dem in der ersten Zeile identisch ist, werden sie in der Reihenfolge sortiert, in der sie
nl
nummeriert sind. Unabhängig davon, in welcher Zeile es auftritt,"${1}"
wird es auf denselben Dateinamen erweitert, den wir ihm entsprechend dernl
Ausgabe zugewiesen haben . Auf diese Weise können Sie die Dateien in Datumsreihenfolge schnell und sicher und in der richtigen Reihenfolge umbenennen.echo
hier mit nerfed . Aber wenn Sie das ausführenecho
und feststellen, dass es zu Ihnen passt, müssen Sie das entfernenecho
.So was:
Oder vielleicht:
Und hier wird es in eine Shell-Funktion eingearbeitet:
Das nutzt die Shell für einige Dinge, die ich mit anderen Dienstprogrammen gemacht habe. Das Konzept ist das gleiche - eine Dateiliste erstellen, auf verschiedene Arten sortieren und die Sortierreihenfolge speichern. Was an diesem Gedanken wirklich anders ist, ist, dass er Verschiebungsvorgänge stapelweise nach Intervallen stapelt, dem Benutzer anzeigt, was zu tun ist, und auf eine Eingabeaufforderung wartet, bevor er fortfährt. Ich habe mich hier damit aufgezeichnet, damit Sie eine Terminalsitzung sehen können, wie es funktioniert.
quelle
20140707_SHOOTNAME_
$LINENO
. Kannst du es versuchenecho $LINENO
? Ich verstehe nicht, warum es nicht unterstützt wird - Sie haben die Anführungszeichen genau kopiert, oder? Sie sind wichtig. Und ich kann nicht dafür sprechenbash
- daher würde ich es nicht empfehlen -,sh
sollte aber damit arbeiten.$LINENO
wird von POSIX angegeben. Auch - setze das Skript nicht im selben Verzeichnis - sonst Änderung des*
an*.NEF
in den beiden ersten und letzten Zeilen.$LINENO
nicht funktioniert, wird dies wahrscheinlich - versuchen, die erste Zeile zu ändern -stat --printf='}" "%z_${SN}_$((i=i+1)).NEF"\n' -- *.NEF |
... und die letzte Zeile zu ...SN=SHOOTNAME sh -s -- *.NEF