Umgang mit Dateinamen mit Sonderzeichen (zB ♫)

30

Ich bin kürzlich auf eine Datei gestoßen, deren Name mit dem Zeichen '♫' beginnt. Ich wollte diese Datei kopieren, einspeisen ffmpegund auf verschiedene andere Arten im Terminal referenzieren. Normalerweise vervollständige ich seltsame Dateinamen automatisch, aber dies schlägt fehl, da ich nicht einmal den ersten Buchstaben eingeben kann.

Ich möchte nicht zur Maus wechseln, um ein Kopieren-Einfügen-Manöver auszuführen. Ich möchte nicht eine Reihe von Codes für mögliche Szenarien auswendig lernen. Meine Ad-hoc-Lösung bestand darin, in das betreffende Zeichen zu wechseln vim, es einzufügen !lsund zu kopieren, es dann zu beenden und in das Terminal einzufügen. Dies hat funktioniert, ist aber ziemlich schrecklich.

Gibt es eine einfachere Möglichkeit, mit solchen Szenarien umzugehen?

HINWEIS: Ich verwende die Fischschale, wenn sich etwas ändert.

Zirkoncode
quelle
7
Können Sie andere Teile der Datei verwenden, um einen regulären Ausdruck für die Arbeit damit zu erstellen? *restoffile.avioder so ähnlich?
SLM
1
In diesem Fall war der verbleibende Name eine Mischung aus Kanji und Katakana (japanische Schrift), also nicht leicht.
ZirconCode
3
Verstanden, dachte ich nur, ich würde fragen. Löst jimmijs antwort es dann? Würde es Ihnen auch etwas ausmachen, einen Screenshot der fehlerhaften Dateien einzufügen? Es wäre wahrscheinlich hilfreich für andere, die dies später lesen könnten.
SLM
1
Ich versuche es jetzt zum Laufen zu bringen. Ich weiß nicht, wie ich einen Screeny posten soll, aber wenn ich die folgenden Befehle ausführe, bekommst du mein touch '♫ 漢字カ' touch '♫ 漢字タ'
falsches
1
Mit zsh können Sie Optionen verwenden, um über die Registerkarte ein Menü zu erhalten, aus dem Sie die entsprechende Datei auswählen können.
Kevin

Antworten:

35

Wenn das erste Zeichen des Dateinamens druckbar ist, aber weder alphanumerisch noch Leerzeichen, können Sie den [[:punct:]]Glob-Operator verwenden:

$ ls *.txt
f1.txt  f2.txt  ♫abc.txt
$ ls [[:punct:]]*.txt
♫abc.txt
jimmij
quelle
Hmm, ich kannte diese Glob-Operatoren nicht, habe sie gelesen und ein wenig gelernt (danke). Sie lösen das Problem, bei dem es sich um eine einzelne seltsame Datei in meinem Verzeichnis handelt. Jetzt habe ich dieses Problem mit einer großen Menge von Dateien, sollte ich eine neue Frage stellen oder diese aktualisieren?
ZirconCode
Ich habe Ihre Antwort akzeptiert und werde morgen das zweite Szenario veröffentlichen, wenn ich Zeit habe. Danke für die Hilfe.
ZirconCode
6

Das einfachste, was mir ls [^a-zA-Z0-9]*in den Sinn kommt, ist und macht den Trick für mich, aber Terdons Antwort ist besser darin, die Aufmerksamkeit auf die extglob-Shell-Option oder sogar einen Shell-unabhängigen Ansatz zu lenken.

user86880
quelle
Dies ist ein anständiger Versuch. Sie könnten ls [^[:alnum:]]*für die gleiche Sache. Aber es ist besser, die Charakterklasse zu verwenden, die es ist , als die Klasse (n), die es nicht ist ; Daher ls [[:punct:]]*wird diese Datei aufgelistet.
Rich
6

ls hat einige Schalter (wie --quote-name, --escape, --literal) für den Umgang mit nicht druckbaren Zeichen, aber in diesem Fall scheint das Zeichen "druckbar", aber nicht "tippbar" zu sein (zumindest auf meiner Tastatur! ), so scheint keiner dieser Schalter zu helfen.

Daher können Sie als allgemeine "Brute Force" -Methode Dateien mit beliebigen Zeichen im Namen entfernen:

$ /bin/ls -1A|cat -n  # list all files (except . and ..), 1 per line, add line numbers
     1  ♫
     2  f1.txt
     3  f2.txt

Suchen Sie die Zeile mit der fehlerhaften Datei. Sehr wahrscheinlich ist es die erste Zeile, aber sagen wir, es ist die fünfte. Zeile 5 drucken und hexadezimal codieren:

$ /bin/ls -1A|sed -n 5p|xxd -g 1
0000000: e2 99 ab 0a                                      ....

Ignorieren Sie das Zeichen 0a (Newline), erstellen Sie eine Escape-Zeichenfolge und verwenden Sie die Option -e von echo, um die Escape-Zeichen zu übersetzen:

$ echo -e '\xe2\x99\xab'
♫

Jetzt können Sie es wie folgt kopieren / verschieben / löschen:

$ cp -vi $(echo -e '\xe2\x99\xab') better_name
‘♫’ -> ‘better_name’

Wenn Sie nicht auf die Verwendung von Shell-Skripten beschränkt sind, können Sie dies auch in Python folgendermaßen tun:

$ python
>>> import os
>>> os.listdir('.')
[ ..., '\xe2\x99\xab', ... ]
>>> print '\xe2\x99\xab'
♫
>>> import shutil
>>> shutil.copy('\xe2\x99\xab', 'better_name')

Mit diesem Ansatz können Sie viele Dateien verarbeiten. Sie müssen lediglich die Logik für die Auswahl der richtigen Dateien schreiben und sie umbenennen, ohne sie zu beschädigen.

for f in os.listdir('.'):
  if not f.isalnum():
    newname = generate_newname(f)
    if not os.path.exists(newname):
      shutil.copy(f, newname)
    else:
      print newname, 'already exists!'
Matthew Breithaupt
quelle
5

Ein ähnlicher Ansatz wäre, alle Dateien aufzulisten, die nicht mit "normalen" Zeichen beginnen. In Bash können Sie dies mit

$ shopt -s extglob
$ ls !([[:alpha:]]*)

Dies scheint jedoch nicht verfügbar zu sein fish, sodass Sie findstattdessen Folgendes verwenden könnten :

$ find . -type f -not -name '[[:alpha:]]*'
terdon
quelle
4

Benennen Sie Symlinks um

Ein Ansatz zum Behandeln von Dateinamen mit Sonderzeichen - als erste Zeichen oder an einer anderen Stelle im Dateinamen - ist das Umbenennen in einfachere Namen .

Dies kann auch verwendet werden, wenn Sie die ursprünglichen Dateinamen beibehalten müssen: Benennen Sie eine Kopie der Dateinamen um.
Dazu können Sie die Dateien kopieren, aber auch Symlinks oder Hardlinks zu den Dateien erstellen und diese umbenennen. cpErstellt Symlinks anstelle von Kopien mit der Option -s( -lfür Hardlinks).

Verwenden Sie "Detox", um Namen zu reinigen

detoxKann zum Umbenennen in saubere Dateinamen verwendet werden. Es benennt Dateien um, um Dateinamen nach verschiedenen Regeln zu bereinigen, die in einer detoxrcDatei definiert sind . Standardmäßig werden die UTF8-Zeichen nur entfernt. Mit der Option werden -s utf_8-onlysie ersetzt durch _:

$ touch '♫ 漢字カ' ♫foo
$ ls -1
♫foo
♫ 漢字カ
$ detox -s utf_8-only * 
$ ls -1                
_ ___
_foo


"Entgiftung" bei Symlinks

Kombiniert mit der Bearbeitung von Symlinks wie oben beschrieben:

$ mkdir orig
$ cd orig 
$ touch '♫ 漢字カ' ♫foo
$ cd ..
$ mkdir clean
$ cd clean 
$ cp -s ../orig/* .
$ ll               
lrwxrwxrwx 1 14 Oct  8 05:52 ♫foo -> ../orig/♫foo
lrwxrwxrwx 1 21 Oct  8 05:52 ♫\ 漢字カ -> ../orig/♫\ 漢字カ
$ ls -1
♫foo
♫ 漢字カ
$ detox --special -s utf_8-only *
$ ll                                
lrwxrwxrwx 1 21 Oct  8 05:52 _\ ___ -> ../orig/♫\ 漢字カ
lrwxrwxrwx 1 14 Oct  8 05:52 _foo -> ../orig/♫foo
Volker Siegel
quelle
2

Ich verwende es nicht fish, aber die Dokumentation besagt, dass Sie ein Unicode-Zeichen eingeben können, indem Sie dem Hex-Zeichencode \u(für 16-Bit-Zeichen) oder \U(für 32-Bit-Zeichen) voranstellen. Ich denke, der Code für ist 491eb, also könnten Sie tun:

mv \U000491ebabc.mp3 abc.mp3

umbenennen ♫abc.mp3.

Beachten Sie, dass Sie die führenden Nullen benötigen, da diese sonst abcam Ende als Hexadezimalziffern und als Teil des Zeichencodes behandelt werden. Für ein 32-Bit-Zeichen müssen Sie 8 Ziffern eingeben.

Barmar
quelle
2

Ich weiß nicht, ob dies bereits 2014 der Fall war, als Sie die Frage gestellt haben, aber in den aktuellen Versionen von fish(ab 2019) können Sie Tabzweimal drücken , um eine Auswahl im zsh-Stil zu erhalten, für die Sie die Pfeiltasten verwenden können Wählen Sie die gewünschte Datei visuell aus, ohne einen Teil des Dateinamens eingeben zu müssen.

Stéphane Chazelas
quelle
2

Fish unterstützt keine Platzhalter für Klammern ¹.

function find_special_filename
    find ! -path './.*' -name '[^-.a-zA-Z0-9_]*' $argv
end

Der Befehl nicht in versteckten Verzeichnissen und zeigt Dateinamen suchen , die mit den Zeichen nicht beginnen letters, digits, . _ -(siehe die Dokumentation find).

Hinweis: $argv Ist eine spezielle Array-Variable (Fish Shell), die die Funktionsargumente enthält. Daher kann der zugrunde liegende Befehl einen beliebigen Ausdruck (z . B. Alias ) erhalten.

find_special_filename -exec mv '{}' misc/ \;

¹ Tatsächlich unterstützt Fish die Erweiterung von Klammern (Array-Variablenerweiterung), Bash verwendet jedoch eine andere Terminologie (Parameter- und Dateinamenerweiterungen).

Fólkvangr
quelle
1

Verwenden zshund tippen Sie, was als nächstes kommt. ZSH unterstützt Fuzzy Auto Complete und kann damit umgehen. (Besonders schön mit dem OH-MY-ZSH-Plugin .)

Martin Thoma
quelle
0

Sie haben nicht gesagt, ob Sie diese problematischen Dateinamen beibehalten möchten. Eine Lösung könnte darin bestehen, das Problem ein für alle Mal zu beheben, indem Sie (einige oder alle) Ihrer Dateien in Namen umbenennen, die Sie durch Ausführen dieses Skripts eingeben können:

#!/bin/sh
for old in *
do
      printf "%s ...? " "$old"
      if read new  &&  [ "$new" != "" ]
      then
             mv -i "$old" "$new"
      fi
done

Daraufhin werden Ihre vorhandenen Dateinamen aufgelistet, gefolgt von ...?. Geben Sie einfach Folgendes ein Enter, um eine Datei unverändert zu lassen. oder geben Sie einen neuen Namen ein, um ihn umzubenennen. Bei -iAuswahl dieser Option werden Sie aufgefordert, das Überschreiben zu bestätigen, wenn Sie den Namen einer anderen vorhandenen Datei angeben.

Dieses Skript kann auf verschiedene Arten geändert werden:

  • Sie können den Platzhalter ( *) beispielsweise einschränkend ändern *.avi *.mov, damit Sie nicht jede Datei überprüfen müssen.
  • Sie könnten die ändern mvzu cp, so dass Sie eine Kopie der Datei mit dem aktuellen Namen behalten und erstellen Sie ein (temporären?) Kopie mit einem typisierbarem Namen.
  • Sie können einen neuen Dateinamen erstellen, der auf dem vorhandenen Dateinamen basiert. Beispielsweise,

    if read pfx  &&  [ "$pfx" != "" ]
    then
            mv -i "$old" "$pfx$old"
    fi
    

    Hiermit können Sie ein Präfix vor den alten Namen setzen. Wenn Sie ein eindeutiges Präfix ausgewählt haben, können Sie die automatische Vervollständigung verwenden.

G-Man sagt, "Monica wiedereinsetzen"
quelle