it-swarm.com.de

Warum sind meine Ordnernamen so gelandet und wie kann ich das mit einem Skript beheben?

Entschuldigung, wenn dies anderswo eine Antwort hat, ich habe keine Ahnung, wie ich nach meinem Problem suchen soll.

Ich habe einige Simulationen auf einem Redhat Linux HPC-Server ausgeführt, und mein Code zum Behandeln der Ordnerstruktur zum Speichern der Ausgabe hatte einen unglücklichen Fehler. Mein Matlab-Code zum Erstellen des Ordners war:

_folder = [sp.saveLocation, 'run_', sp.run_number, '/'];
_

dabei war _sp.run_number_ eine ganze Zahl. Ich habe vergessen, es in einen String zu konvertieren, aber aus irgendeinem Grund war es immer noch erfolgreich, mkdir(folder); (in matlab) auszuführen. Tatsächlich liefen die Simulationen reibungslos und die Daten wurden im entsprechenden Verzeichnis gespeichert.

Wenn nun die Ordnerstruktur abgefragt/gedruckt wird, erhalte ich die folgenden Situationen:

  • Wenn ich versuche, die automatische Vervollständigung zu aktivieren: _run_ run_^A/ run_^B/ run_^C/ run_^D/ run_^E/ run_^F/ run_^G/ run_^H/ run_^I/_
  • Wenn ich ls verwende: _run_ run_? run_? run_? run_? run_? run_? run_? run_? run_? run_?_.
  • Wenn ich mit rsync auf meinen Mac übertrage, zeigt die Option _--progress_ Folgendes an: _run_\#003/_ usw., wobei (ich nehme an) die Zahl mit der Ganzzahl in _sp.run_number_ übereinstimmt, die auf drei Ziffern aufgefüllt ist, sodass der 10. Lauf ausgeführt wird _run_\#010/_
  • Wenn ich die Ordner im Finder ansehe, sehe ich _run_ run_ run_ run_ run_ run_ run_ run_ run_ run_?_
  • Wenn ich mir this frage ansehe und den Befehl _ls | LC_ALL=C sed -n l_ verwende, bekomme ich:
_run_$
run_\001$
run_\002$
run_\003$
run_\004$
run_\005$
run_\006$
run_\a$
run_\b$
run_\t$
run_$
_

Ich kann mit keiner dieser Darstellungen cd in die Ordner schaffen.

Ich habe Tausende dieser Ordner, daher muss ich dies mit einem Skript beheben. Welche dieser Optionen ist die richtige Darstellung des Ordners? Wie kann ich programmgesteuert auf diese Ordner verweisen, um sie mithilfe eines Bash-Skripts mit einem ordnungsgemäß formatierten Namen umzubenennen? Und ich denke aus Neugier, wie zum Teufel ist das überhaupt passiert?

15
Phill

Sie können das Dienstprogramm Perl rename (auch bekannt als prename oder file-rename) Verwenden, um die Verzeichnisse umzubenennen.

HINWEIS : Dies ist nicht zu verwechseln mit rename aus util-linux Oder einer anderen Version.

rename -n 's/([[:cntrl:]])/ord($1)/eg' run_*/

Dies verwendet Perls ord() - Funktion, um jedes Steuerzeichen im Dateinamen durch die Ordnungszahl für dieses Zeichen zu ersetzen. z.B. wird ^A 1, ^B wird 2 usw.

Die Option -n Ist für einen Trockenlauf vorgesehen, um zu zeigen, was renamewürde tun würde, wenn Sie es zulassen. Entfernen Sie es (oder ersetzen Sie es durch -v Für eine ausführliche Ausgabe), um es tatsächlich umzubenennen.

Der Modifikator e in der Operation s/LHS/RHS/eg Bewirkt, dass Perl die RHS (die Ersetzung) als Perl-Code ausführt, und der Modifikator $1 Sind die übereinstimmenden Daten (das Steuerzeichen) aus dem LHS.

Wenn Sie in den Dateinamen mit Nullen aufgefüllte Zahlen möchten, können Sie ord() mit sprintf() kombinieren. z.B.

$ rename -n 's/([[:cntrl:]])/sprintf("%02i",ord($1))/eg' run_*/ | sed -n l
rename(run_\001, run_01)$
rename(run_\002, run_02)$
rename(run_\003, run_03)$
rename(run_\004, run_04)$
rename(run_\005, run_05)$
rename(run_\006, run_06)$
rename(run_\a, run_07)$
rename(run_\b, run_08)$
rename(run_\t, run_09)$

Die obigen Beispiele funktionieren wenn und nur wennsp.run_number In Ihrem Matlab-Skript lag im Bereich von 0..26 (also wurden Steuerzeichen in den Verzeichnisnamen erzeugt).

Um mit JEDEM 1-Byte-Zeichen (d. H. Von 0..255) umzugehen, verwenden Sie:

rename -n 's/run_(.)/sprintf("run_%03i",ord($1))/e' run_*/

Wenn sp.run_number> 255 sein könnte, müssten Sie Perls unpack() -Funktion anstelle von ord() verwenden. Ich weiß nicht genau, wie matlab ein nicht konvertiertes int in einem String ausgibt, also müssen Sie experimentieren. Siehe perldoc -f unpack Für Details.

z.B. Im Folgenden werden sowohl vorzeichenlose 8-Bit- als auch 16-Bit-Werte entpackt und auf 5 Stellen mit Nullen aufgefüllt:

 rename -n 's/run_(.*)/sprintf("run_%05i",unpack("SC",$1))/e' run_*/
26
cas

Und ich denke aus Neugier, wie zum Teufel ist das überhaupt passiert?

folder = [sp.saveLocation, 'run_', sp.run_number, '/'];

dabei war sp.run_number eine ganze Zahl. Ich habe vergessen, es in einen String zu konvertieren, aber aus irgendeinem Grund läuft mkdir(folder); (in matlab) immer noch erfolgreich.

Es scheint also, dass mkdir([...]) in Matlab die Mitglieder des Arrays verkettet, um den Dateinamen als Zeichenfolge zu erstellen. Aber Sie haben ihm stattdessen eine Nummer gegeben, und Zahlen sind das, was die Zeichen auf einem Computer wirklich sind. Wenn also sp.run_number1 War, gab es Ihnen das Zeichen mit dem Wert 1 Und dann das Zeichen mit dem Wert 2 Usw.

Dies sind Steuerzeichen, sie haben keine druckbaren Symbole, und das Drucken auf einem Terminal hätte andere Konsequenzen. Stattdessen werden sie häufig durch verschiedene Arten von Escapezeichen dargestellt: \001 (Oktal), \x01 (Hex), ^A Sind alle gängigen Darstellungen für das Zeichen mit dem Wert 1. Das Zeichen mit dem Wert Null ist etwas anders. Es ist das NUL-Byte, mit dem das Ende einer Zeichenfolge in C und in den Unix-Systemaufrufen markiert wird.

Wenn Sie höher als 31 sind, werden druckbare Zeichen angezeigt, 32 ist Leerzeichen (allerdings nicht sehr sichtbar), 33 = !, 34 = " Usw.

Damit,

  • run_ run_^A/ run_^B/ - Das erste run_ Entspricht dem mit einem Null-Byte, der String endet dort. Die anderen zeigen, dass Ihre Shell die Steuercodes gerne mit ^A Anzeigt. Die Notation weist auch darauf hin, dass das Zeichen mit dem numerischen Wert 1 als eingegeben werden kann Ctrl-A, obwohl Sie der Shell mitteilen müssen, dass sie nicht als Steuerzeichen, sondern als Literal interpretiert werden soll, Ctrl-VCtrl-A sollte das zumindest in Bash tun.

  • ls: run_ run_? run_? - ls druckt nicht gerne nicht druckbare Zeichen auf dem Terminal, sondern ersetzt sie durch Fragezeichen.

  • rsync: run_\#003/ - das ist neu für mich, aber die Idee ist dieselbe, der Backslash markiert eine Flucht und der Rest ist der numerische Wert des Zeichens. Es scheint mir, dass die Zahl hier oktal ist, wie im allgemeineren \003.

  • mit dem Befehl ls | LC_ALL=C sed -n l ... run_\006$run_\a$run_\b$run_\t$ - \a, \b und \t sind C-Escapezeichen für Alarm (Glocke), Rücktaste bzw. Tabulator. Sie haben die numerischen Werte 7, 8 und 9, daher sollte klar sein, warum sie nach \006 Kommen. Die Verwendung dieser C-Escapezeichen ist eine weitere Möglichkeit, die Steuerzeichen zu markieren. Die nachgestellten Dollarzeichen markieren die Zeilenenden.

Was cd betrifft, sollte cd run_ Unter der Annahme, dass meine Annahmen richtig sind, in dieses eine Verzeichnis ohne ein ungerades nachfolgendes Zeichen verschoben werden, und cd run_? Sollte einen Fehler geben, da das Fragezeichen lautet Ein Glob-Zeichen, das mit einem einzelnen Zeichen übereinstimmt, und es gibt mehrere übereinstimmende Dateinamen, aber cd erwartet nur einen.

Welche dieser Optionen ist die richtige Darstellung des Ordners?

In gewissem Sinne alle ...

In Bash können Sie die Escapezeichen \000 Und \x00 In $'...' Anführungszeichen verwenden, um die Sonderzeichen darzustellen, also $'run_\033 (Oktal) oder $'run_\x1b' entsprechen dem Verzeichnis mit dem Zeichenwert 27 (was zufällig ESC ist). (Ich glaube nicht, dass Bash Escapezeichen mit Dezimalzahlen unterstützt.)

die Antwort von cas enthält ein Skript, mit dem diese umbenannt werden können, sodass ich nicht dorthin gehe.

11
ilkkachu

Am einfachsten wäre es, den falschen Dateinamen und den richtigen Dateinamen in derselben Umgebung zu erstellen, in der das Missgeschick aufgetreten ist, und dann die Ordner einfach in die richtigen Namen zu verschieben/umzubenennen.

Um Kollisionen zwischen vorhandenen Namen zu vermeiden, verwenden Sie besser einen anderen Zielordner.

./saveLocationA/wrongname1 -> ./saveLocationB/correctname1
./saveLocationA/wrongname2 -> ./saveLocationB/correctname2
./saveLocationA/wrongname3 -> ./saveLocationB/correctname3

Wenn möglich, würde ich es vorziehen, das Skript zu reparieren und es einfach erneut auszuführen. Das Beheben eines seltsamen Post-Mortem-Fehlers kostet wahrscheinlich mehr und kann neue Probleme verursachen.

Viel Glück!

3
Peter