Mit einem Hochdurchsatzmikroskop erzeugen wir Tausende von Bildern. Nehmen wir an, unser System nennt sie:
ome0001.tif
ome0002.tif
ome0003.tif
ome0004.tif
ome0005.tif
ome0006.tif
ome0007.tif
ome0008.tif
ome0009.tif
ome0010.tif
ome0011.tif
ome0012.tif
...
Wir möchten alternativ c1
und c2
in Bezug auf den numerischen Wert der Bilder einfügen und dann die ursprüngliche Nummerierung so ändern, dass jede aufeinanderfolgende c1
und c2
dieselbe inkrementelle Nummer enthält, wobei die numerische Reihenfolge (1, dann 2 ... dann 9, dann 10) berücksichtigt wird ) statt alphanumerischer Reihenfolge (1, dann 10, dann 2 ...).
In meinem Beispiel würde das ergeben:
ome0001c1.tif
ome0001c2.tif
ome0002c1.tif
ome0002c2.tif
ome0003c1.tif
ome0003c2.tif
ome0004c1.tif
ome0004c2.tif
ome0005c1.tif
ome0005c2.tif
ome0006c1.tif
ome0006c2.tif
...
Wir konnten dies nicht über die Terminal-Befehlszeile tun (Biologe spricht ...).
Jeder Vorschlag wäre sehr dankbar!
command-line
batch-rename
Philippe P.
quelle
quelle
(1, then 2... then 9, then 10)
Ihrer Aussageome0001.tif
>ome0001c1.tif
undome0002.tif
>ome0001c2.tif
und so weiter? Neugierig auf den Mikroskoptyp.Antworten:
rename
Führt eine Massenumbenennung durch und kann die von Ihnen benötigte Arithmetik ausführen.Verschiedene GNU / Linux-Distributionen haben unterschiedliche Befehle
rename
mit unterschiedlicher Syntax und unterschiedlichen Funktionen. In Debian, Ubuntu und einigen anderen Betriebssystemenrename
ist das Perl-Umbenennungsprogrammprename
. Es ist sehr gut für diese Aufgabe geeignet.Zuerst empfehle ich zu sagen
rename
, dass Sie nur zeigen sollen , was es tun würde, indem Sie es mit der-n
Flagge ausführen:Das sollte dir zeigen:
Angenommen, Sie möchten dies tun, führen Sie es ohne die
-n
Flagge aus (dh entfernen Sie es einfach-n
):Dieser Befehl ist etwas hässlich - obwohl immer noch eleganter als die Verwendung einer Schleife in Ihrer Shell - und vielleicht wird jemand mit mehr Perl-Erfahrung als ich eine schönere Lösung veröffentlichen.
Ich empfehle Olis Tutorial Bulk-Umbenennungsdateien in Ubuntu. Die kürzeste Einführung in den Umbenennungsbefehl für eine sanfte Einführung in das Schreiben von
rename
Befehlen.So
rename
funktioniert dieser spezielle Befehl:Folgendes
s/\d+/sprintf("%04dc%d", int(($& - 1) \/ 2) + 1, 2 - $& % 2)/e
bewirkt:s
Mittel, um nach zu ersetzendem Text zu suchen./\d+/
entspricht einer oder mehreren (+
) Ziffern (\d
). Dies entspricht Ihre0001
,0002
und so weiter.sprintf("%04dc%d", int(($& - 1) / 2) + 1, 2 - $& % 2)
wird erstellt.$&
repräsentiert das Match./
Normalerweise wird der Ersetzungstext beendet, es wird jedoch\/
ein Literal erstellt/
(dies ist eine Unterteilung, wie unten beschrieben)./e
Mittel, um den Ersatztext als Code auszuwerten .(Versuchen Sie es mit nur
/
statt/e
am Ende, aber achten Sie darauf, die-n
Flagge zu behalten ! )Somit sind Ihre neuen Dateinamen die Rückgabewerte von
sprintf("%04dc%d", int(($& - 1) \/ 2) + 1, 2 - $& % 2)
. Also, was ist dort los?sprintf
Gibt formatierten Text zurück. Das erste Argument ist die Formatzeichenfolge, in die Werte eingefügt werden.%04d
verbraucht das erste Argument und formatiert es als Ganzzahl mit einer Breite von 4 Zeichen.%4d
würde führende Nullen weglassen, daher%04d
wird benötigt. Von niemandem abgedeckt zu werden%
,c
bedeutet nur einen wörtlichen Buchstabenc
. Dann%d
verbraucht das zweite Argument und formatiert sie als eine Ganzzahl (mit Standardformatierung).int(($& - 1) / 2) + 1
1 subtrahiert von der Anzahl von den ursprünglichen Dateinamen extrahierten, teilt es durch 2, kürzt den Bruchteil ( dasint
tut), dann fügt 1. Die arithmetische sendet0001
und0002
zu0001
,0003
und0004
zu0002
,0005
und0006
nach0003
, und so weiter.2 - $& % 2
Der Rest der Division der aus dem ursprünglichen Dateinamen extrahierten Zahl durch 2 (%
macht das), was 0 ist, wenn es gerade ist, und 1, wenn es ungerade ist. Es subtrahiert dann das von 2. Diese Arithmetik sendet0001
an1
,0002
an2
,0003
an1
,0004
an2
und so weiter.Schließlich
ome????.tif
handelt es sich um einen Glob , den Ihre Shell zu einer Liste aller Dateinamen im aktuellen Verzeichnis erweitert, die mit genau vier beliebigen Zeichen beginnen, mit diesenome
enden.tif
und genau vier Zeichen dazwischen haben.Diese Liste wird an den
rename
Befehl übergeben, der versucht,-n
alle Dateien, deren Namen eine Übereinstimmung mit dem Muster enthalten , umzubenennen (oder mitzuteilen, wie er umbenannt werden soll)\d+
.\d+
mit\d{4}
in den Ausdruck in den oben gezeigten Befehle erscheinen regelmäßig, um sicherzustellen , dass sie nicht umbenannt werden, oder einfach nur die Ausgabe mit produziert prüfen-n
sorgfältig, was Sie ohnehin tun sollten.\d+
anstatt\d{4}
zu vermeiden, dass der Befehl komplexer als nötig wird. (Es gibt viele verschiedene Möglichkeiten, es zu schreiben.)quelle
Ich habe eine Methode verwendet, um dies in Bash zu tun, basierend auf der Idee, dass wenn die Zahl im Dateinamen gerade ist, wir sie durch zwei teilen und hinzufügen wollen
c2
, und wenn die Zahl ungerade ist, wollen wir eine hinzufügen und dann durch zwei teilen und hinzufügenc1
. Die getrennte Behandlung von Dateien mit ungeraden und geraden Nummern auf diese Weise ist viel länger als die Bash-Methode von Eliah Kagan, und ich stimme zu, dass die Verwendungrename
wie in dieser anderen Antwort von Eliah Kagan der kluge Weg ist, aber diese Art von Ansatz kann in einigen Situationen nützlich sein.Ein kleiner Vorteil gegenüber der Verwendung eines Bereichs wie
{0000...0012}
ist, dass nur versucht wird, vorhandene Dateien zu bearbeiten, sodass es sich nicht beschwert, wenn die Dateien nicht vorhanden sind. Sie erhalten jedoch immer noch unlogisch nummerierte Dateien, wenn Lücken vorhanden sind. Im zweiten Teil meiner Antwort finden Sie einen Weg, der dieses Problem nicht hat.In einer Zeile sieht es schrecklich aus:
Hier ist das als Skript:
Die
echo
es vor denmv
Anweisungen dienen nur zum Testen. Entfernen Sie sie, um die Dateien tatsächlich umzubenennen, wenn Sie sehen, was Sie tun möchten.Anmerkungen
Testen Sie, ob die Zahl gerade ist (dh das Teilen durch 2 ergibt keinen Rest)
Ich habe verwendet
bc
, das nicht versucht, Zahlen mit führenden Nullen als Oktalzahlen zu behandeln, obwohl ich die Nullen einfach mit einer anderen Zeichenfolgenerweiterung hätte entfernen können, da ich die Zahlen sowieso mit fester Breite formatieren werde.Als nächstes konstruieren Sie den neuen Namen für die geradzahligen Dateien:
%04d
wird durch diebc <<< "$h/2"
im 4-stelligen Format ausgegebene Zahl ersetzt , die mit führenden Nullen aufgefüllt ist (also 0 = 0000, 10 = 0010 usw.).Benennen Sie die Originaldatei mit dem erstellten neuen Namen um
-v
für ausführlich,-n
für No-Clobber (überschreiben Sie keine Dateien, die bereits den beabsichtigten Namen haben, falls vorhanden) und--
um Fehler durch Dateinamen zu vermeiden, die mit beginnen-
(aber da der Rest meines Skripts erwartet, dass Ihre Dateien benannt werden,ome[somenumber].tif
denke ich, ich ' Ich füge es nur aus Gewohnheit hinzu.Die Lücken füllen
Nach einigem Basteln und mehr Hilfe von Eliah Kagan habe ich einen prägnanteren Weg gefunden, um die Namen zu erhöhen, was den Vorteil hat, die Lücken zu füllen. Das Problem bei dieser Methode ist, dass nur eine Zahl inkrementiert, eine einfache Arithmetik für diese Zahl durchgeführt, sie formatiert und in den Dateinamen eingefügt wird. Bash denkt (sozusagen) "ok, hier ist die nächste Datei, ich gebe ihr den nächsten Namen", ohne auf den ursprünglichen Dateinamen zu achten. Dies bedeutet, dass neue Namen erstellt werden, die sich nicht auf die alten Namen beziehen , sodass Sie die Umbenennung nicht logisch rückgängig machen können und die Dateien nur dann in der richtigen Reihenfolge umbenannt werden, wenn ihre Namen bereits so sind, dass sie verarbeitet werden in der richtigen Reihenfolge. Dies ist in Ihrem Beispiel der Fall, das mit Nullen aufgefüllte Zahlen mit fester Breite enthält. Wenn Sie jedoch Dateien mit dem Namen "z.
2
8
,10
,45
Würden sie in der Reihenfolge verarbeitet werden10
,2
,45
,8
, das ist wahrscheinlich nicht das, was Sie wollen.Wenn dieser Ansatz angesichts all dessen für Sie geeignet ist, können Sie dies folgendermaßen tun:
oder
Anmerkungen
i=0
eine Variable initiieren((i++))
Erhöhen Sie die Variable um eins (dies zählt die Iterationen der Schleife).printf -v new
Fügen Sie die folgende Anweisung in die Variable einnew
"ome%04dc%d.tif"
der neue Dateiname mit den Zahlenformaten, die durch die nachfolgend genannten Zahlen ersetzt werden$(((i+1)/2))
Die Häufigkeit, mit der die Schleife ausgeführt wurde, plus eins, geteilt durch 2Dies funktioniert auf der Grundlage, dass Bash nur eine ganzzahlige Division durchführt. Wenn wir also eine ungerade Zahl durch 2 teilen, erhalten wir dieselbe Antwort wie beim Teilen der vorhergehenden geraden Zahl durch 2:
$(((i+1)%2+1))
Der Rest nach dem Teilen der Häufigkeit, mit der die Schleife ausgeführt wurde, plus eins durch zwei plus eins. Dies bedeutet, wenn die Nummer der Iteration ungerade ist (z. B. der erste Lauf), ist die Ausgabe1
, und wenn die Nummer der Iteration gerade ist (z. B. der zweite Lauf), ist die Ausgabe2
, gebenc1
oderc2
Früher habe ich ,
i=0
weil dann an jedem beliebigen Punkt während des Laufes, der Werti
wird die Anzahl der Male die Schleife ausgeführt wurde , die für die Fehlersuche nützlich sein könnte , wie es auch die Ordnungsnummer der Datei verarbeitet werden wird ( das heißt , wenni=69
wir verarbeiten die 69. Datei). Wir können die Arithmetik jedoch vereinfachen, indem wir mit einem anderen beginneni
, zum Beispiel:Es gibt viele Möglichkeiten, dies zu tun :)
echo
Nur zum Testen - entfernen Sie, wenn Sie das gewünschte Ergebnis sehen.Hier ist ein Beispiel für diese Methode:
quelle
Sie können dafür eine Shell-Schleife schreiben, wenn Sie wirklich wollen.
Wenn Sie einen Befehl möchten, der auf Systemen funktioniert, die keinen haben
rename
oder dessenrename
Befehl nicht istprename
, oder wenn Sie möchten, dass er von Personen, die Bash, aber nicht Perl kennen, etwas besser verstanden wird, oder aus einem anderen Grund möchten Sie dies als implementieren Eine Schleife in Ihrer Shell, die denmv
Befehl aufruft , können Sie. (Ansonsten empfehle ich dierename
Methode in meiner anderen Antwort dazu.)Ubuntu hat Bash 4, bei dem die Klammererweiterung führende Nullen beibehält und daher auf
{0001..0012}
erweitert0001 0002 0003 0004 0005 0006 0007 0008 0009 0010 0011 0012
. Dies ist nur in Situationen angebracht, in denen Sie tatsächlich alle Dateien in einem Bereich haben. Basierend auf der Problembeschreibung in Ihrer Frage scheint dies der Fall zu sein. Andernfalls würde es immer noch funktionieren, aber Sie würden eine ganze Reihe von Fehlermeldungen für die Lücken erhalten, die es schwierig machen würden, andere Fehler zu bemerken, die tatsächlich wichtig sein könnten. Ersetzen Sie0012
durch Ihre tatsächliche Obergrenze.Da dieser Befehl bereits
echo
angezeigt wirdmv
, werden nur diemv
Befehle gedruckt, die ausgeführt werden würden, ohne sie tatsächlich auszuführen: 1Dies verwendet dieselbe Grundidee wie in meiner
rename
Antwort , sowohl was die Arithmetik betrifft als auch was die Bedeutung%04d
und%d
die Formatzeichenfolgen betrifft. Dies könnte getan werden{1..12}
, aber dann wäre es noch komplizierter, da zwei$(
)
Befehlsersetzungen mitprintf
anstelle von nur einer erforderlich wären .Bitte denken Sie daran, dass das
-n
Inrename -n
nicht dasselbe bedeutet wie das-n
Inmv -n
. Beim Ausführen werdenrename -n
Dateien überhaupt nicht verschoben. Durch das Ausführen werdenmv -n
Dateien verschoben, es sei denn, es müsste eine vorhandene Datei am Ziel überschrieben werden, um dies zu tun. Diesmv -n
gibt Ihnen die Sicherheit, die Sie automatisch erhaltenrename
(es sei denn, Sie führenrename -f
). Entfernen Sie denecho
folgenden Befehl, damit der oben gezeigte Befehl Dateien tatsächlich verschiebt :So funktioniert diese Bash-Schleife:
for i in {0001..0012}
führt die Befehle nachdo
zwölf Mal aus,i
wobei jedes Mal ein anderer Wert angenommen wird. Diese Schleife hat zuvor nur einen solchen Befehldone
, der das Ende des Schleifenkörpers kennzeichnet. (Wenn die Steuerung dies trifft,done
geht sie konzeptionell zur nächsten Iteration der Schleife über, miti
dem nächsten Wert.) Dieser eine Befehl lautet:$i
erscheint einige Male in der Schleife. Dies ist eine Parametererweiterung und wird durch den aktuellen Wert von ersetzti
.ome$i.tif
expandiert nach einem derome0001.tif
,ome0002.tif
,ome0003.tif
, usw., je nachdem , welcher Werti
hat. Das Einfügen der führenden Nullen durch Schreiben{0001..0012}
anstelle von{1..12}
macht dieses Argumentmv
, das den alten Namen der Datei angibt, einfach zu schreiben.$(
)
ist Befehlsersetzung . Darin führe ich einenprintf
Befehl aus, der den gewünschten Text des zweiten Arguments ausgibtmv
, der den neuen Namen der Datei angibt. Das Ganze wird in geschlossene"
"
Anführungszeichen so unerwünschte Erweiterungen - insbesondere Globbing und Wort Spaltung vermieden --are. In Befehl Substitution,$(...)
ersetzt wird durch Ausgabe durch die Ausführung des Befehls erzeugt...
.Der Befehl, der den Zieldateinamen ausgibt, lautet wie folgt:
%04d
und%d
haben die gleiche Bedeutung wie in Perlssprintf
Funktion, die von verwendet wurderename
.$((...))
wird durch das Ergebnis der Auswertung des Ausdrucks ersetzt...
.10#$i
nimmt den Wert voni
($i
) und behandelt ihn als Basis-10- Zahl (10#
). Dies ist hier notwendig, da Bash Zahlen mit führenden0
s als Oktal behandelt . 2 Im Inneren können$((
))
Sie normalerweise nur den Namen einer Variablen schreiben, um damit zu rechnen (dhi
anstelle von$i
). Dies$i
wird jedoch auch unterstützt und10#$i
ist einer der wenigen Fälle, in denen er im Inneren benötigt wird$((
))
.rename
, außer dass die Division in Bash automatisch eine ganzzahlige Division ist - sie schneidet automatisch den Bruchteil ab -, sodass nichts verwendet werden muss, was der Perl-int
Funktion entspricht.1 Ein Fehler in der Syntaxhervorhebung, die für Bash-Code auf dieser Site verwendet wird, führt derzeit dazu, dass alles nach dem
#
ausgegraut wird. Ein nicht zitierter Code#
startet normalerweise einen Kommentar in Bash, in diesem Fall jedoch nicht . Sie brauchen sich darüber keine Sorgen zu machen - Ihr Bash-Interpreter macht nicht den gleichen Fehler.2 Perl behandelt Zahlen mit führenden
0
s auch als Oktal. Doch mitrename
der Anpaßvariable$&
ist eigentlich ein String - das ist Textverarbeitung, nachdem alle. Perl erlaubt die Verwendung von Zeichenfolgen, als wären sie Zahlen, und wenn dies der Fall ist, werden führende0
s in der Zeichenfolge nicht dazu führen, dass sie als Oktalzahl behandelt werden! Wenn man denrename
Weg mit dieser längeren, schwierigeren und weniger robusten Shell-Loop-Methode vergleicht, fällt eine häufige Beobachtung ein: Perl ist seltsam, aber es erledigt den Job.quelle