Warum sind meine Ordnernamen so gelandet und wie kann ich dies mithilfe eines Skripts beheben?

15

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

Ich habe einige Simulationen auf einem Red Hat Linux HPC-Server ausgeführt, und mein Code für die Verwaltung der Ordnerstruktur zum Speichern der Ausgabe wies einen unglücklichen Fehler auf. Mein Matlab-Code zum Erstellen des Ordners war:

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

wo sp.run_numberwar eine ganze Zahl. Ich habe vergessen, es in eine Zeichenfolge umzuwandeln, aber aus irgendeinem Grund läuftmkdir(folder); (in Matlab) immer noch erfolgreich. Tatsächlich liefen die Simulationen reibungslos und die Daten wurden im entsprechenden Verzeichnis gespeichert.

Jetzt, wenn die Ordnerstruktur abgefragt / gedruckt wird, erhalte ich die folgenden Situationen:

  • Wenn ich versuche, automatisch zu vervollständigen: run_ run_^A/ run_^B/ run_^C/ run_^D/ run_^E/ run_^F/ run_^G/ run_^H/ run_^I/
  • Wenn ich benutze ls:run_ run_? run_? run_? run_? run_? run_? run_? run_? run_? run_? .
  • Wenn ich mit rsync auf meinen Mac übertrage, --progresszeigt die Option: run_\#003/etc. mit (ich nehme an) der Zahl, die mit der Ganzzahl in übereinstimmtsp.run_number drei Ziffern aufgefüllt , also ist der 10. Laufrun_\#010/
  • Wenn ich die Ordner im Finder ansehe, sehe ich run_ run_ run_ run_ run_ run_ run_ run_ run_ run_?
  • Wenn ich diese Frage betrachte und den Befehl verwende, ls | LC_ALL=C sed -n lbekomme ich:
run_$
run_\001$
run_\002$
run_\003$
run_\004$
run_\005$
run_\006$
run_\a$
run_\b$
run_\t$
run_$

Ich kann cdmit keiner dieser Darstellungen in die Ordner gelangen.

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 schätze aus Neugier, wie zum Teufel ist das überhaupt passiert?

Phill
quelle
4
"Wenn ich versuche, die Registerkarte" Autovervollständigen "aufzurufen: ... Wenn ich zu tippen versuche ..." Warum tippe ich und lasse die Autovervollständigung nicht abschließen, wenn für Sie? Auch ^Awird nicht wörtlich ^gefolgt A, sondern Strg-A (Sie können es mit Strg-V Strg-A eingeben, da Strg-A im Allgemeinen eine Abkürzung für die Shell ist).
Muru
@muru, das nicht funktioniert ... Ich komme so weit run_und ich muss etwas eingeben
Phill
Sorry, kommentiert, bevor ich deine Bearbeitung gesehen habe, die es schafft, mich per CD
einzuspielen
Mögliches Duplikat des Select Unicode Dateinamens in Bash
muru
9
Übrigens, der "gewisse Grund", warum mkdir in matlab dies tat, ist, dass die EINZIGEN ungültigen Zeichen in einem Datei- oder Verzeichnisnamen auf Unix-Dateisystemen NUL und Schrägstriche sind /. Jedes andere Zeichen ist gültig, einschließlich Steuerzeichen. Ich weiß nicht, was matlab getan hätte, wenn sp.run_number 0 gewesen wäre (wahrscheinlich entweder mit einem Fehler run_abgebrochen oder erzeugt , da das NUL-Byte den Verzeichnisnamen-String beenden würde). Dies wäre natürlich auch problematisch für 16-Bit-Werte (oder höher), die ein NUL-Byte enthalten, und würde sich auch nach dem Endian des Systems richten, auf dem matlab ausgeführt wird.
cas

Antworten:

26

Sie können das Perl- renameDienstprogramm (auch bekannt als prenameoder file-rename) verwenden, um die Verzeichnisse umzubenennen.

HINWEIS: Dies ist nicht zu verwechseln mit renameaus util-linux, oder jeder anderen Version.

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

Hierbei wird die Perl- ord()Funktion verwendet, um jedes Steuerzeichen im Dateinamen durch die Ordnungszahl für dieses Zeichen zu ersetzen. zB ^Awird 1, ^Bwird 2, etc.

Die -nOption ist ein Probelauf, um zu zeigen, was passieren rename würde , wenn Sie es zulassen. Entfernen Sie es (oder ersetzen Sie es durch -veine ausführliche Ausgabe), um es tatsächlich umzubenennen.

Der eModifikator in der s/LHS/RHS/egOperation veranlasst Perl, die RHS (die Ersetzung) als Perl-Code auszuführen, und das $1sind die übereinstimmenden Daten (das Steuerzeichen) aus der LHS.

Wenn Sie in den Dateinamen ord()mit Nullen aufgefüllte Zahlen verwenden möchten, können Sie diese mit kombinieren sprintf(). 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 genau dann, wenn sp.run_number in Ihrem Matlab-Skript ein Wert im Bereich von 0..26 angegeben wurde (sodass Steuerzeichen in den Verzeichnisnamen erzeugt wurden).

Um mit JEDEM 1-Byte-Zeichen (dh ab 0..255) umzugehen, würden Sie Folgendes verwenden:

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

Wenn sp.run_number> 255 sein könnte, müssten Sie unpack()stattdessen die Perl- Funktion verwenden ord(). Ich weiß nicht genau, wie matlab ein nicht konvertiertes int in einer Zeichenfolge ausgibt. Sie müssen also experimentieren. Siehe perldoc -f unpackfür weitere Einzelheiten.

Das folgende Beispiel entpackt vorzeichenlose 8-Bit- und 16-Bit-Werte und füllt sie mit Nullen auf eine Breite von 5 Stellen auf:

 rename -n 's/run_(.*)/sprintf("run_%05i",unpack("SC",$1))/e' run_*/
cas
quelle
Danke für die Details! Ich versuche, es mit der -nOption zu testen , aber es sagt mir, dass es eine ungültige Option ist - die Versionsinformationen geben mir rename from util-linux 2.23.2also nicht sicher, ob es die gleiche Funktion ist
Phill
3
Aus diesem Grund habe ich die Perl- Version des renameDienstprogramms angegeben. util-linux‚s renameist ganz anders, viel weniger in der Lage, und die Befehlszeilenoptionen sind nicht kompatibel. Wenn Sie Debian oder ähnliches ausführen, versuchen Sie, das file-renamePaket zu installieren . Installieren Sie andernfalls das entsprechende Paket für Ihre Distribution. Möglicherweise ist es bereits installiert. Versuchen Sie es mit "Ausführen" prenameoder file-renamestatt "Nur" rename.
cas
Ja, ich dachte das wäre der Fall. Ich werde sehen, ob ich einen davon zum Arbeiten bringen kann. Nochmals vielen Dank, dass Sie sich die Zeit genommen haben, mir zu helfen!
Phill
11

Und ich schätze aus Neugier, wie zum Teufel ist das überhaupt passiert?

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

wo sp.run_numberwar eine ganze Zahl. Ich habe vergessen, es in einen String umzuwandeln, aber aus irgendeinem Grund läuft es mkdir(folder); (in Matlab) noch gelungen.

Es scheint also, dass mkdir([...])in Matlab die Mitglieder des Arrays verkettet werden, 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. Also, wann sp.run_numberwar 1, gab es Ihnen das Zeichen mit Wert 1, und dann das Zeichen mit Wert 2usw.

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) ^Asind alle gebräuchlichen Darstellungen für das Zeichen mit Wert 1. Das Zeichen mit dem Wert Null ist ein bisschen 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 ein Leerzeichen (allerdings nicht sehr gut sichtbar), 33 = !, 34 = "usw.

So,

  • run_ run_^A/ run_^B/- Der erste run_entspricht dem mit einem Null-Byte, der String endet dort. Die anderen zeigen, dass Ihre Shell die Steuercodes gerne mit anzeigt ^A. 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 interpretieren Ctrl-V Ctrl-Asoll, zumindest in Bash.

  • ls: run_ run_? run_?- lsdruckt keine nicht druckbaren Zeichen auf dem Terminal aus, 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 im Oktal ist, wie in der allgemeineren \003.

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

Was cdunter der Annahme , meine Annahmen recht, cd run_in dieser ein einzigen Verzeichnis ohne einen ungeradeen hinteren Charakter gehen sollte, und cd run_?soll einen Fehler geben , da das Fragezeichen ein glob Zeichen , das für ein einzelnes Zeichen übereinstimmt, und es gibt mehr passenden Dateinamen, sondern cdnur erwartet einen.

Welche dieser Optionen ist die richtige Darstellung des Ordners?

In gewisser Weise alle ...

In Bash können Sie das \000und \x00in $'...'Anführungszeichen setzen, um die Sonderzeichen darzustellen, also $'run_\033(oktal) oder $'run_\x1b'dem Verzeichnis mit dem Zeichenwert 27 (zufällig ESC) entsprechen. (Ich glaube nicht, dass Bash Escape-Zeichen mit Dezimalzahlen unterstützt.)

cas Antwort hat ein Skript, um diese umzubenennen, also werde ich nicht dorthin gehen.

ilkkachu
quelle
Wenn es sich um GNU handelt ls, gibt es einige Anführungszeichenoptionen, einschließlich -b/ --escapeund --quoting-style=oder der QUOTING_STYLEUmgebungsvariablen, um zu steuern, wie nicht druckbare Zeichen angezeigt werden. Ich glaube nicht, dass es eine Option gibt, die Oktal-Flucht gegenüber den Charakterversionen bevorzugt.
Toby Speight
3

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

Verwenden Sie einen anderen Zielordner, um Kollisionen zwischen vorhandenen Namen zu vermeiden.

./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 erneut auszuführen. Das Reparieren von seltsamen Bugs kostet wahrscheinlich mehr und kann neue Probleme verursachen.

Viel Glück!

Peter
quelle