Wie kann ich eine Datei löschen, deren Dateiname keine druckbaren Zeichen enthält?

46

Ich habe es irgendwie geschafft, eine Datei zu erstellen, die keinen Dateinamen zu haben scheint. Im folgenden Thread habe ich einige Informationen dazu gefunden, wie Sie weitere Details der Datei abrufen können.

Ich habe jedoch einige der aufgeführten Vorschläge ausprobiert und kann die Datei anscheinend nicht löschen. Ich bin nicht sicher, was ich getan habe, um es zu erstellen, aber es ist passiert, als ich versucht habe, eine XML-Datei zu kopieren.

Einige Informationen in der Datei lauten wie folgt:

> ls -lb
total 296
-rw-r--r--   1 voyager  endeavor  137627 Jan 12 12:49 \177

> file *
:               XML document

> ls -i
 417777   

Ich habe versucht, mithilfe des Inum-Schalters herauszufinden, ob dies der narrensicherste Weg ist, es loszuwerden. Das Beispiel am Ende des unten verlinkten Threads ist für mich jedoch fehlgeschlagen. Beispiel war:

> find -inum 41777 -exec ls -al {} \;
find: illegal option -- i
find: [-H | -L] path-list predicate-list

Also habe ich zuerst versucht, die Pfadliste wie folgt zu verwenden, aber das hat auch nicht funktioniert:

> find . -inum 41777 -exec ls -al {} \;

Ich bin nicht sicher, was das nicht druckbare Zeichen \ 177 ist oder wie ich das an einen rmBefehl übergeben kann, aber ich möchte wirklich sicherstellen, dass ich keine anderen Dateien / Verzeichnisse vermassle, wenn ich versuche, diese Datei zu löschen.

Herr Elch
quelle
1
\177ist das ASCII- DELZeichen.
Keith Thompson
9
417777! = 41777
ein
Hervorragender Punkt Michael. Das ist wahrscheinlich der Grund, warum mein Befehl nie funktioniert hat.
Mr Moose
@KeithThompson Ist es oktal ohne Führung 0?
Katze
1
@cat: In diesem Zusammenhang ja. Es folgt der C-Syntax für Zeichenfolgen- und Zeichenliterale.
Keith Thompson

Antworten:

46

Die Datei hat einen Namen, besteht jedoch aus nicht druckbaren Zeichen. Wenn Sie ksh93, bash, zsh, mksh oder FreeBSD sh verwenden, können Sie versuchen, es zu entfernen, indem Sie den nicht druckbaren Namen angeben. Stellen Sie zunächst sicher, dass der Name richtig ist mit: ls -ld $'\177' Wenn die richtige Datei angezeigt wird, verwenden Sie rm:rm $'\177'

Ein anderer (etwas riskanterer) Ansatz ist die Verwendung rm -i -- *. Mit der Option -i muss rm vor dem Entfernen einer Datei bestätigt werden, damit Sie alle Dateien überspringen können, die Sie behalten möchten, außer der einen.

Viel Glück!

antje-m
quelle
1
Ich vermute, rm -i *das hätte in diesem Fall nicht funktioniert. Aufgrund der Zeilenumbrüche würde die Shell *zu etwas erweitert, rmdas nicht als Dateiname erkannt wird.
Keith Thompson
6
@KeithThompson: Die Glob-Erweiterung in der Shell kann nicht weiter interpretiert werden. Der erweiterte Name würde keine neue Zeile enthalten, es sei denn, er enthält eine.
Christoffer Hammarström
@ ChristofferHammarström: Hmm. Ich werde ein paar Experimente machen und weiter kommentieren.
Keith Thompson
@ ChristofferHammarström: Der erweiterte Name enthält eine neue Zeile, da der Dateiname Zeilenumbrüche enthält. Aber es scheint, ich habe bashund GNU unterschätzt rm. Auf meinem System rm *, rm -i *und rm Ctrl-V DEL TAB ENTERalle Arbeiten korrekt, auch wenn der Dateiname enthält ein Newline - Zeichen (I verwendet "\177foo\nbar\n"). Einige Befehle behandeln solche Dateinamen nicht gut, aber die GNU-Tools scheinen robust zu sein. Nicht-GNU-Versionen der gleichen Tools verhalten sich möglicherweise nicht so gut. In jedem Fall ist es hilfreich, die verschiedenen Tricks in diesen Antworten zu kennen.
Keith Thompson
1
@KeithThompson, jede Shell verarbeitet das Globbing von Dateien korrekt, nicht nur Bash, und rmteilt niemals Wörter, egal ob GNU rmoder nicht. Die Shell erweitert die Globs und übergibt bei Ausführung des aufgerufenen Befehls die resultierenden Dateinamen als durch Null getrennte Argumente (im C-Code). Was gefährlich ist Rohr eine Liste von Dateien zu etwas , das verwendet Zeilenumbrüche als Trennzeichen; Siehe Warum ist das Schleifen über Finds Ausgabe eine schlechte Übung?
Wildcard
23

Für diejenigen, vimdie es im aktuellen Arbeitsverzeichnis ausführen:

$ vim ./ 

und navigieren Sie mit den Pfeiltasten oder zur Datei j/k. Drücken Sie dann Shift+Dund bestätigen Sie den Löschvorgang mit y.


quelle
Ich habe generell Angst vor Vim, aber das hat wirklich gut
funktioniert
9

Es gibt wahrscheinlich eine Möglichkeit, den Dateinamen an zu übergeben rm, aber wenn Sie Bedenken haben, etwas durcheinander zu bringen, können Sie einen GUI-Dateimanager verwenden. Emacs wird mit einem Verzeichnisbearbeitungsmodus geliefert, den Sie verwenden können, wenn Sie ihn installiert haben:

  1. Öffnen Sie den Ordner in emacs. Sie können emacs /path/to/folderEmacs ausführen oder öffnen, Esc+ drücken xund ausführen dired, wodurch Sie zur Eingabe des Pfads aufgefordert werden

    http://so.mrozekma.com/unix-dired-delete1.png

  2. Gehen Sie zu der Zeile mit der Datei, die Sie löschen möchten, und drücken Sie d. Sie sollten Dam linken Rand neben der Datei ein sehen:

    http://so.mrozekma.com/unix-dired-delete2.png

  3. Drücken Sie x, um Ihre Änderungen zu speichern. Sie werden aufgefordert, sicherzustellen, dass Sie die Datei löschen möchten. Presse y:

    http://so.mrozekma.com/unix-dired-delete3.png

Michael Mrozek
quelle
1
Sieht nach einer großartigen Idee aus, aber ich kann anscheinend keine Emacs auf diesem Computer finden. Auf die Gefahr eines heiligen Krieges ... kann dies in vim getan werden?
Mr Moose
2
Für diejenigen, die es verwenden, vimführen Sie es im aktuellen Arbeitsverzeichnis aus: vim ./und navigieren Sie mit den Pfeiltasten zu der Datei. Drücken Sie dann Shift+Dund bestätigen Sie den Löschvorgang mit y.
@hesse Wow. Nichts, von dem ich erwartet hätte, dass ich vimes unterstütze
Michael Mrozek
1
@MichaelMrozek stimmte zu, es hat all diese Eigenschaften, die ich gelegentlich zu entdecken neige.
1
@ Kevin Nyan-Modus: nyan-mode.buildsomethingamazing.com
Tim
8

Sie haben bereits gezeigt, file *dass die Shell glob ( *) in der Lage ist, diese Datei aufzunehmen, also machen Sie jetzt einfach eine rmauf diesem Glob.

  • Wechseln Sie in das Verzeichnis, in dem sich die Datei befindet.
  • Lauf rm -i *
  • Geben Sie nfür alle Dateien außer der mit dem scheinbar unsichtbaren Dateinamen ein
Patrick
quelle
7

Die Datei hat tatsächlich einen Namen, besteht jedoch aus nicht druckbaren Zeichen.

Eine einfache Methode besteht darin, sich auf die Vervollständigung der Shell zu verlassen: Drücken Sie Tabwiederholt, bis der „seltsame“ Dateiname eingefügt wird. Sie müssen Ihre Shell so konfiguriert haben, dass Sie zwischen möglichen Abschlüssen wechseln können:

  • In bash müssen Sie aufrufen menu-complete, was nicht standardmäßig gebunden ist, sondern eher complete, was Tabstandardmäßig gebunden ist . Alternativ können Sie Esc *Vervollständigungen für alle Dateien einfügen und diejenigen, die Sie nicht löschen möchten, aus der Befehlszeile entfernen.
  • In zsh sind die Standardeinstellungen in Ordnung. Sie müssen haben setopt auto_menuoder setopt menu_completeeinstellen.

Wenn die Vervollständigung in Ihrer Shell nicht hilfreich ist, können Sie mit rm -i -- *Ausnahme dieser bestimmten Datei "Nein" anrufen und antworten. Wenn der Dateiname nicht mit einem druckbaren Zeichen beginnt, können Sie die Übereinstimmungen auf Dateien beschränken, deren erstes Zeichen nicht in einem Satz druckbarer Zeichen enthalten ist:

rm -i [!!-~]*
rm -i [![:print:]]*
rm -i -- [!a-z]

(Passen Sie auf, ob Ihr Muster möglicherweise mit einer aufgerufenen Datei übereinstimmt -f, was rmals Option behandelt würde.)

Eine andere Methode ist der Aufruf ls -i, um den Inode der Datei zu finden (ein Inode identifiziert eine Datei auf einem bestimmten Dateisystem eindeutig) und dann find -inumauf diese bestimmte Datei zuzugreifen. Diese Methode ist vor allem dann nützlich, wenn das Verzeichnis viele Dateien enthält.

ls -i
# note the inode number 12345
find . -xdev -inum 12345 -delete

Wenn Sie findkeine -deleteOption haben, rufen Sie an rm:

find . -xdev -inum 12345 -exec rm -- {} \;

(Ja, ich weiß, dass das meiste bereits veröffentlicht wurde. Die Antworten mit den relevanten Informationen machen dies jedoch komplizierter, als es sein sollte.)

Gilles 'SO - hör auf böse zu sein'
quelle
4

Versuchen Sie es mit echo -e, um den Charakter zu erhalten \177, und xargsübergeben Sie ihn dann an rm. echoEs werden keine Dezimal-Escape-Zeichen verwendet. In Hex konvertieren: Stellt fest, dass 177es sich um ein Oktal handelt. echoerfordert ein \0(Literal, kein Null-Byte) vor:

echo -ne '\0177\0' | xargs -0 rm
Kevin
quelle
Wollen Sie damit sagen, dass \ xb1 \ 0 die hexadezimale Darstellung von \ 177 ist?
Mr Moose
@MrMoose \xb1ist dezimal 177, \0beendet es mit Null und -0weist xargsan, einen Namen mit Null anstelle eines Namens mit Zeilenumbruch zu verwenden.
Kevin
Ich verwende bash unter SunOS und als ich Ihren Befehl ausprobierte, bekam ich xargs: illegale Option - 0. Ich habe die Manpage angesehen und konnte keine Option für die Nullbeendigung finden. Ich habe es jetzt geschafft, das Problem zu beheben. Siehe die Antwort als Antwort markiert.
Mr Moose
Ihr Status echosendet 2 Dateinamen an xargs und dann weiter an rm... Der zweite Dateiname lautet \n.. Dies führt entweder zu einem Fehler oder zum Löschen einer Datei mit diesem Namen ('\ n')
Peter. O
@perer Ja, das ist mir gerade aufgefallen. Ich fügte hinzu -n, um die Newline loszuwerden.
Kevin
3

Ich kann Ihnen nur garantieren , dass die Datei hat einen Namen hat. Es ist einfach ein Name, der nicht druckbare Zeichen enthält.

Wenn rmdies nicht funktioniert hat, hilft es wahrscheinlich nicht, die Ausgabe von findmit der -inumOption als Argument für rmzu verwenden. Es wird nur das gleiche Argument rmmit dem gleichen Problem übergeben.

Die Datei ist die einzige in diesem Verzeichnis, oder?

Das erste, was ich versuchen würde, ist, cdin das Verzeichnis zu gehen, es einzugeben rm ./und dann die Tabulatortaste zu drücken. Dadurch sollte das Argument auf den tatsächlichen Namen der Datei erweitert werden, und das Vorhergehende ./sollte verhindern rm, dass das Argument als etwas anderes als ein Dateiname interpretiert wird.

Eine andere Lösung besteht darin, cdin das übergeordnete Verzeichnis zu wechseln und dann das Verzeichnis rm -r(oder, falls erforderlich, rm -rf) zu verwenden. Das sollte das Verzeichnis und seinen gesamten Inhalt unabhängig vom Namen entfernen. Sie können dann verwenden mkdir, um das Verzeichnis neu zu erstellen (und möglicherweise chmodseine Berechtigungen wiederherzustellen).

EDIT:

Bei ls -lbnochmaliger Betrachtung Ihrer Ausgabe denke ich, dass der Dateiname mit einem ASCII- DELZeichen beginnt (was nicht schlimm ist, nicht schwerwiegend) und ein oder mehrere Zeilenumbrüche enthält (was wirklich schlimm ist). Soweit ich rmweiß , kann der Befehl einen Zeilenumbruch nicht als Teil eines Dateinamens interpretieren.

Aber der unlink()Systemaufruf kann. Hier ist ein von mir zusammengestelltes Perl-Skript, das die Dateien im aktuellen Verzeichnis durchläuft und Sie nach jedem fragt, ob Sie es entfernen möchten. Es wird kein externer Befehl rmzum Entfernen der Dateien verwendet. Daher sollte es in der Lage sein, alle vom Dateisystem unterstützten komischen Zeichen (außer ASCII NULund /) zu verarbeiten.

Tun rm -roder rm -rfauf dem enthaltenden Verzeichnis sollte immer noch funktionieren, aber wenn Sie nur eine einzelne Datei entfernen möchten, können Sie dies versuchen.

#!/usr/bin/perl

use strict;
use warnings;

opendir my $DIR, '.' or die ".: $!\n";
my @files = sort grep { -f } readdir $DIR;
closedir $DIR;

foreach my $file (@files) {
    my $pfile = printable($file);
    print "Remove $pfile? ";
    my $answer = scalar <STDIN>;
    if ($answer =~ /^[Yy]/) {
        print "Removing $pfile\n";
        unlink $file or warn "Unable to remove $pfile: $!\n";
    }
}

sub printable {
    my($s) = @_;
    $s =~ s/[^ -~]/?/g;
    return $s;
}

(Eine andere Lösung, wenn das Verzeichnis andere Dateien enthält, die Sie behalten möchten, besteht darin, alle anderen Dateien in ein temporäres Verzeichnis zu verschieben, das Verzeichnis zu speichern und neu zu erstellen und die anderen Dateien zurück zu verschieben.)

(Oh, und was auch immer Sie getan haben, um diese Datei zu erstellen, versuchen Sie es nicht noch einmal!)

Keith Thompson
quelle
1

Wenn Sie mit dem Befehl genau diese Datei finden können, findkönnen Sie das -deletePrädikat verwenden. Seien Sie vorsichtig und geben Sie -deleteeinen letzten Parameter für den Befehl find ein, da dies sonst sehr weh tut.

Michał Šrajer
quelle
1

Du bist nah dran. Schritt für Schritt, hier erfahren Sie, wie Sie die Datei nach Inode-Nummer löschen.

Ermitteln Sie zunächst mit die Inode-Nummer der gewünschten Datei ls -li. Die Inode-Nummer befindet sich in der ersten Spalte der Ausgabe.

Zum Beispiel:

$ls -li
311010 -rw-rw-r-- 1 me me 3995 Apr  6 16:27 -???\# ;-)

In diesem Fall lautet die Inode-Nummer 311010

Verwenden Sie finddiese Option, um die Datei anhand der Inode-Nummer zu suchen.

find . -inum 311010 

Stellen Sie sicher, dass findnur der Name der zu löschenden Datei zurückgegeben wird. Zum Beispiel:

$find . -inum 311010
./-???\# ;-)

Wenn Sie sicher sind, dass finddie richtige Datei gefunden wurde, übergeben Sie den -deleteParameter an find. Es wird die Datei für Sie löschen.

find . -inum 311010 -delete
Christian Long
quelle
0

Die anderen Antworten sind großartig und funktionieren in fast allen Umgebungen.

Wenn jedoch eine GUI ausgeführt wird, öffnen Sie einfach das Verzeichnis in Nautilus, Delphin, Konqueror oder Ihrem bevorzugten Dateimanager, und Sie sollten in der Lage sein, jede Datei, die einen unkooperativen Namen hat, mit ein paar Mausklicks zu sehen und zu löschen .

Wenn Sie kein normaler Emacs- oder Vim-Benutzer sind (wie in mehreren anderen Antworten beschrieben), ist dies möglicherweise der einfachste Weg.

Joe
quelle
0

Hatte ein ähnliches Problem mit einer Datei namens "\ 033" (dem eigentlichen "Escape" -Zeichen).

for x in $( ls | awk '!/^[A-Z]/ && !/^[a-z]/ && !/^[0-9]/');do rm -i -- $x ; done

Mit dem obigen Befehl werden Sie aufgefordert, Dateien im aktuellen Verzeichnis zu entfernen, die nicht mit einem Buchstaben oder einer Zahl beginnen.

Signal15
quelle
0

Stattdessen können Sie das aktuelle Verzeichnis in umbenennen DirX_OLD, ein neues Verzeichnis mit dem Namen erstellen DirXund alle erforderlichen Dateien von DirX_OLDnach verschieben DirX. Nach dem Kopieren der Dateien können Sie diese löschenDirX_OLD

user106382
quelle
0

Nur für den Fall, dass es jemandem hilft, füge ich meine zwei Cent hinzu. Ich konnte die Dateinamen mit statdem folgenden Platzhalter abrufen:

stat -c %N *

Ausgabe:

`\220g\201\acontexts'
`\220g\201\alogins'
`\220g\201\amodules'
`\220g\201\apolicy'
`\220g\201\asetrans.conf'

Dann könnte ich ANSI-C-Anführungszeichen verwenden (wie in der akzeptierten Antwort verwendet), um auf die Dateien zuzugreifen:

rm $'\220g\201\asetrans.conf'
miken32
quelle
0

Jede Datei hat einen Namen, man muss nur genau den finden.

Ich werde diese Dateien als Beispiele verwenden:

$ touch $'\177' $'\001\002' $'\033\027' a b abc $'a\177b'

Diese Dateien werden wie ?gewohnt angezeigt ls:

$ ls
??  ?  ?002  a  abc  b

Wenn Sie lsdie -QOption zulassen , sollte jedoch klar sein, wie der tatsächliche Dateiname lautet:

$ ls -1iQ *
26739122 "\001\002"
26739117 "\033\027"
26739115 "\177"
26739118 "a"
26739121 "a\177b"
26739120 "abc"
26739119 "b"

Dies sind die Inode-Nummern und "Anführungszeichen" in der 1Spalte der Dateien in pwd.

Das nutzt die Fähigkeit einer (POSIX) Shell, Erweiterungen (Globbing) zu verwenden:

Um die Namen mit einem nicht druckbaren Zeichen zu haben:

$ ls -1iQ *[![:print:]]*
26739122 "\001\002"
26739117 "\033\027"
26739115 "\177"
26739121 "a\177b"

Und um Dateien aufzulisten, die möglicherweise nur nicht druckbare Zeichen enthalten:

$ ls -1iQ [![:print:]]*
26739122 "\001\002"
26739117 "\033\027"
26739115 "\177"

-iUm sie dann selektiv (über die (interaktive) Option) zu entfernen, verwenden Sie:

$ rm -i [![:print:]]*
rm: remove regular file ''$'\001\002'? n
rm: remove regular file ''$'\033\027'? n
rm: remove regular file ''$'\177'? n

Sie müssen nur auswählen, welche gelöscht werden sollen, indem Sie ydie oben stehende Frage beantworten .

Isaac
quelle
0

Wenn Sie eine Bash mit Autovervollständigung haben, funktioniert dies möglicherweise für Sie. Ich habe das Zeichen eingegeben, das in der Verzeichnisliste angezeigt wurde. Dann habe ich die Autovervollständigung ausgelöst und das Ding in etwas Druckbares umbenannt.

Folgendes hat bei mir funktioniert:

$ ll
-rw-r--r--.  1 xxxxxxxx  xxxxx 25608 Oct 11 11:11 ?
$ mv ?  
(hit the [tab] and it gets extended to ...)
$ mv ^[
(now complete the command and rename to something printable)
$ mv ^[ weirdchar
$ ll
-rw-r--r--.  1 xxxxxxxx  xxxxx 25608 Oct 11 11:11 weirdchar
(now delete)
$ rm weirdchar
Sascha
quelle
-4
rm -dfvr /"(null)" 

arbeitete für mich.

Ryan S
quelle