Bagaimana saya bisa menghapus file dengan nama file yang memiliki karakter non-cetak


46

Saya entah bagaimana berhasil membuat file yang sepertinya tidak memiliki nama file. Saya menemukan beberapa informasi tentang cara mendapatkan rincian lebih lanjut dari file di utas berikut .

Namun, saya mencoba beberapa saran yang tercantum dan sepertinya tidak dapat menghapus file. Saya tidak yakin apa yang saya lakukan untuk membuatnya, tetapi itu terjadi ketika mencoba menyalin file xml.

Beberapa info pada file tersebut adalah sebagai berikut;

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

> file *
:               XML document

> ls -i
 417777   

Saya mencoba untuk menemukan menggunakan saklar inum dan kemudian pipa itu ke rm karena itu sepertinya cara paling mudah untuk menghilangkannya. Namun, contoh yang diberikan di bagian bawah utas yang ditautkan di bawah gagal untuk saya. Contohnya adalah:

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

jadi saya mencoba menggunakan daftar path terlebih dahulu seperti berikut, tetapi itu tidak berhasil:

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

Saya tidak yakin apa karakter yang tidak dapat dicetak \ 177 atau bagaimana saya bisa meneruskannya ke rmperintah, tapi saya benar-benar ingin memastikan saya tidak mengacaukan file / direktori lain dalam upaya saya menghapus file ini.


1
\177adalah DELkarakter ASCII .
Keith Thompson

9
417777! = 41777
CVn

Poin bagus Michael. Mungkin itulah sebabnya perintah saya tidak pernah berhasil.
Tuan Moose

@KeithThompson Apakah ini oktal tanpa petunjuk 0?
kucing

1
@ kucing: Dalam konteks ini, ya. Ini mengikuti sintaks C untuk string dan karakter literal.
Keith Thompson

Jawaban:


46

File memiliki nama, tetapi terbuat dari karakter yang tidak dapat dicetak. Jika Anda menggunakan ksh93, bash, zsh, mksh atau FreeBSD sh, Anda dapat mencoba menghapusnya dengan menentukan nama yang tidak dapat dicetak. Pertama pastikan bahwa nama itu benar: ls -ld $'\177' Jika itu menunjukkan file yang tepat, maka gunakan rm:rm $'\177'

Pendekatan lain (sedikit lebih berisiko) adalah menggunakan rm -i -- *. Dengan opsi -i rm memerlukan konfirmasi sebelum menghapus file, sehingga Anda dapat melewati semua file yang ingin Anda simpan kecuali yang satu.

Semoga berhasil!


1
Saya menduga itu rm -i *tidak akan berhasil dalam kasus ini; karena baris baru, shell akan meluas *ke sesuatu yang rmtidak akan dikenali sebagai nama file.
Keith Thompson

6
@KeithThompson: Ekspansi gumpalan di shell tidak tunduk pada interpretasi lebih lanjut. Tidak akan ada baris baru dalam nama yang diperluas kecuali jika berisi itu.
Christoffer Hammarström

@ ChristofferHammarström: Hmm. Saya akan melakukan beberapa percobaan dan berkomentar lebih lanjut.
Keith Thompson

@ ChristofferHammarström: Ada baris baru di nama yang diperluas karena nama file berisi karakter baris baru. Tapi sepertinya saya sudah diremehkan bashdan GNU rm. Pada sistem saya, rm *, rm -i *, dan rm Ctrl-V DEL TAB ENTERsemua pekerjaan dengan benar, bahkan jika nama file berisi karakter baris baru (saya menggunakan "\177foo\nbar\n"). Beberapa perintah tidak menangani nama file seperti itu dengan baik, tetapi alat GNU tampak kuat; versi non-GNU dari alat yang sama mungkin tidak berlaku juga. Bagaimanapun, berbagai trik dalam jawaban ini berguna untuk diketahui.
Keith Thompson

1
@KeithThompson, shell apa pun akan menangani penggumpalan file dengan benar, tidak hanya Bash, dan rmtidak pernah melakukan segala bentuk pemisahan kata apakah itu GNU rmatau bukan. Shell memperluas gumpalan dan, ketika mengeksekusi perintah yang dipanggil, ia meneruskan nama file yang dihasilkan sebagai argumen dipisahkan nol (dalam kode C). Yang berbahaya adalah menyalurkan daftar file ke sesuatu yang menggunakan baris baru sebagai pembatas; lihat Mengapa mengulangi hasil praktik buruk?
Wildcard

23

Bagi yang menggunakan vimjalankan di direktori kerja saat ini:

$ vim ./ 

dan arahkan ke file dengan tombol panah atau j/k. Lalu tekan Shift+Ddan konfirmasi penghapusan dengan y.


saya biasanya takut vim, tapi itu bekerja dengan sangat baik
tofutim

9

Mungkin ada cara untuk meneruskan nama file rm, tetapi jika Anda khawatir akan mengacaukan apa pun, Anda dapat menggunakan manajer file GUI. Emacs hadir dengan mode pengeditan direktori yang dapat Anda gunakan jika sudah diinstal:

  1. Buka folder emacs. Anda dapat menjalankan emacs /path/to/folder, atau membuka emacs, tekan Esc+ x, dan jalankan dired, yang akan meminta path

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

  2. Pindah ke baris dengan file yang ingin Anda hapus dan tekan d. Anda akan melihat Ddi margin kiri di sebelah file:

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

  3. Tekan xuntuk menyimpan perubahan Anda. Ini akan meminta untuk memastikan Anda ingin menghapus file; tekan y:

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


1
Sepertinya ide yang bagus, tetapi sepertinya saya tidak dapat menemukan emacs di mesin ini. Dengan risiko memulai perang suci ... dapatkah ini dilakukan dalam vim?
Tuan Moose

2
Bagi yang menggunakan vimjalankan di direktori kerja saat ini: vim ./dan navigasikan ke file dengan tombol panah. Lalu tekan Shift+Ddan konfirmasi penghapusan dengan y.

@hesse Wow. Bukan sesuatu yang saya harapkan vimuntuk mendukung
Michael Mrozek

1
@MichaelMrozek setuju, ia memiliki semua fitur yang kadang-kadang cenderung saya temukan.


8

Anda telah menunjukkan dengan file *bahwa shell glob ( *) dapat mengambil file ini, jadi sekarang lakukan saja rmpada glob tersebut.

  • Ubah ke direktori file.
  • Lari rm -i *
  • Masukkan nsemua file kecuali file dengan nama file yang tampaknya tidak terlihat

7

File sebenarnya memiliki nama, tetapi terbuat dari karakter yang tidak dapat dicetak.

Metode yang mudah adalah dengan mengandalkan penyelesaian shell: tekan Tabberulang kali hingga nama file "aneh" dimasukkan. Anda harus sudah mengonfigurasi shell Anda untuk siklus di antara kemungkinan penyelesaian:

  • Di bash, Anda perlu memohon menu-complete, yang tidak terikat secara default, bukan complete, yang terikat Tabsecara default. Atau, gunakan Esc *untuk memasukkan penyelesaian untuk semua file, dan hapus yang Anda tidak ingin hapus dari baris perintah.
  • Di zsh, pengaturan default baik-baik saja; Anda perlu memiliki setopt auto_menuatau setopt menu_completemengatur.

Jika penyelesaian tidak membantu dalam shell Anda, Anda dapat memanggil rm -i -- *dan menjawab "tidak" kecuali untuk file khusus ini. Jika nama file tidak dimulai dengan karakter yang dapat dicetak, Anda dapat membatasi kecocokan untuk file yang karakter pertamanya tidak berada dalam serangkaian karakter yang dapat dicetak:

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

(Hati-hati jika pola Anda mungkin cocok dengan file yang dipanggil -f, yang rmakan diperlakukan sebagai opsi.)

Metode lain adalah menelepon ls -iuntuk menemukan inode file (sebuah inode secara unik mengidentifikasi file pada sistem file yang diberikan), kemudian find -inumuntuk beroperasi pada file tertentu. Metode ini sebagian besar berguna ketika direktori berisi banyak file.

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

Jika Anda findtidak memiliki -deleteopsi, hubungi rm:

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

(Ya, saya tahu bahwa sebagian besar sudah diposting. Tetapi jawaban dengan informasi yang relevan membuat ini lebih rumit dari yang seharusnya.)


4

Coba gunakan echo -euntuk mendapatkan karakter \177, lalu xargsmeneruskannya rm. echotidak mengambil jalan keluar desimal, jadi konversikan ke hex: Ternyata 177is oktal; echomembutuhkan \0(literal, bukan byte nol) sebelum:

echo -ne '\0177\0' | xargs -0 rm

Apakah Anda mengatakan bahwa \ xb1 \ 0 adalah representasi hex dari \ 177?
Tuan Moose

@MrMoose \xb1adalah desimal 177, \0null-mengakhiri itu, dan -0memberitahu xargsuntuk mengambil nama yang diakhiri null alih-alih yang diakhiri baris baru.
Kevin

Saya menggunakan bash di SunOS dan ketika saya mencoba perintah Anda, saya mendapat xargs: opsi ilegal - 0. Saya melihat halaman manual dan tidak bisa melihat opsi untuk terminasi nol. Saya berhasil mendapatkan perbaikan untuk masalah ini sekarang. Lihat respons yang ditandai sebagai jawaban.
Tn. Moose

Anda echo, apa adanya, mengirim 2 nama file ke xargs, dan kemudian ke rm... nama file kedua adalah \n.. Ini menghasilkan kesalahan, atau menghapus file dari nama itu ('\ n')
Peter. O

@perer Ya, saya baru sadar. Saya menambahkan -nuntuk menyingkirkan baris baru.
Kevin

3

Saya hanya bisa menjamin Anda bahwa file tersebut memang memiliki nama. Itu hanya nama yang mengandung karakter yang tidak dapat dicetak.

Jika rmtidak berhasil, maka gunakan output finddengan -inumopsi sebagai argumen rmtidak mungkin membantu; itu hanya akan memberikan argumen yang sama rm, dengan masalah yang sama.

File adalah satu-satunya di direktori itu, kan?

Hal pertama yang saya coba adalah cdmasuk ke direktori, lalu ketik rm ./, lalu tekan tombol Tab. Ini harus memperluas argumen ke nama sebenarnya file, dan sebelumnya ./harus mencegah rmdari menafsirkan argumen sebagai sesuatu selain nama file.

Solusi lain adalah dengan cdke direktori induk, kemudian gunakan rm -r(atau, jika perlu, rm -rf) pada direktori. Itu harus menghapus direktori dan semua isinya, terlepas dari nama. Anda kemudian dapat menggunakan mkdiruntuk membuat ulang direktori (dan mungkin chmoduntuk mengembalikan izinnya).

SUNTING :

Melihat ls -lboutput Anda lagi, saya pikir nama file dimulai dengan DELkarakter ASCII (yang buruk tidak fatal) dan berisi satu atau lebih karakter baris baru (yang benar-benar buruk). Sejauh yang saya tahu, rmperintah tidak dapat menafsirkan baris baru sebagai bagian dari nama file.

Tetapi unlink()panggilan sistem bisa. Berikut adalah skrip Perl yang saya buat bersama yang akan diulang melalui file di direktori saat ini, dan meminta Anda untuk masing-masing apakah Anda ingin menghapusnya. Itu tidak menggunakan perintah eksternal suka rmmenghapus file, sehingga harus dapat menangani karakter lucu yang didukung sistem file (apa pun selain ASCII NULdan /).

Melakukan rm -ratau rm -rfpada direktori yang berisi harus tetap berfungsi, tetapi jika Anda hanya ingin menghapus satu file, Anda dapat mencoba ini.

#!/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;
}

(Solusi lain, jika ada file lain di direktori yang ingin Anda simpan, adalah memindahkan semua file lain ke direktori sementara, lalu nuke dan buat kembali direktori dan pindahkan file lainnya kembali.)

(Oh, dan apa pun yang Anda lakukan untuk membuat file itu, cobalah untuk tidak melakukannya lagi!)


1

Jika Anda dapat menemukan persis file yang menggunakan findperintah, maka Anda dapat menggunakan -deletepredikat. Berhati-hatilah, dan buat -deleteparameter terakhir dari perintah find atau akan sangat menyakitkan ...


1

Anda dekat. Langkah demi langkah, inilah cara menghapus file dengan nomor inode.

Pertama, temukan nomor inode dari file yang Anda inginkan, gunakan ls -li. Nomor inode akan berada di kolom pertama output.

Sebagai contoh:

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

Dalam hal ini, nomor inode adalah 311010

Gunakan finduntuk mencari file dengan nomor inode.

find . -inum 311010 

Pastikan findhanya mengembalikan nama file yang ingin Anda hapus. Sebagai contoh:

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

Setelah Anda yakin findmenemukan file yang tepat, maka berikan -deleteparameter ke find. Ini akan menghapus file untuk Anda.

find . -inum 311010 -delete

0

Jawaban lainnya bagus dan akan bekerja di hampir semua lingkungan.

Tetapi, jika Anda memiliki gui yang berjalan, cukup buka direktori di nautilus, dolphin, konqueror, atau pengelola file favorit Anda dan Anda seharusnya dapat dengan mudah melihat dan menghapus file apa pun yang memiliki nama tidak kooperatif dengan beberapa klik mouse. .

Jika Anda bukan pengguna emacs atau vim biasa (seperti yang ditampilkan dalam beberapa jawaban lain), ini mungkin cara termudah untuk melakukannya.


0

Punya masalah serupa dengan file bernama "\ 033" (karakter "Escape" yang sebenarnya).

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

Di atas akan meminta Anda untuk menghapus file di direktori saat ini yang tidak dimulai dengan huruf atau angka.


0

Sebagai gantinya, Anda dapat mengganti nama direktori saat ini menjadi DirX_OLD, membuat direktori baru dengan nama DirXdan memindahkan semua file yang diperlukan dari DirX_OLDke DirX. Setelah menyalin file, Anda dapat menghapusDirX_OLD


0

Kalau-kalau itu membantu siapa pun saya akan menambahkan dua sen saya senilai. Saya bisa mendapatkan nama file menggunakan statwildcard seperti ini:

stat -c %N *

Keluaran:

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

Kemudian saya bisa menggunakan string ANSI C-dikutip (seperti yang digunakan dalam jawaban yang diterima) untuk mengakses file:

rm $'\220g\201\asetrans.conf'

0

Setiap file memiliki nama, Anda hanya perlu menemukan yang mana.

Saya akan menggunakan file ini sebagai contoh:

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

File-file itu akan ditampilkan seperti ?biasa ls:

$ ls
??  ?  ?002  a  abc  b

Tetapi jika Anda lsmengizinkan -Qopsi itu harus jelas apa nama file aslinya:

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

itu adalah nomor inode dan nama "Dikutip" di 1kolom file dalam pwd.

Itu menggunakan hability dari shell (POSIX) untuk menggunakan ekspansi (globbing):

Untuk memiliki nama dengan karakter non-cetak:

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

Dan untuk membuat daftar file yang mungkin hanya memiliki karakter non-cetak:

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

Kemudian, untuk secara selektif (opsi -i(interaktif)) menghapusnya gunakan:

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

Anda hanya perlu memilih mana yang akan dihapus dengan menjawab ypertanyaan di atas.


0

Jika Anda memiliki bash dengan pelengkapan otomatis, ini mungkin cocok untuk Anda. Saya mengetik karakter yang ditampilkan dalam daftar direktori. Kemudian saya memicu pelengkapan otomatis dan menamai ulang hal itu menjadi sesuatu yang dapat dicetak.

Inilah yang bekerja untuk saya:

$ 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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.