Làm cách nào tôi có thể xóa một tệp mà tên tệp có ký tự không in


46

Tôi bằng cách nào đó đã quản lý để tạo một tệp dường như không có tên tệp. Tôi tìm thấy một số thông tin liên quan đến cách lấy thêm chi tiết của tệp trong chuỗi sau .

Tuy nhiên, tôi đã thử một số đề xuất được liệt kê và dường như không thể xóa tệp. Tôi không chắc chắn những gì tôi đã làm để tạo ra nó, nhưng nó đã xảy ra trong khi cố gắng sao chép một tệp xml.

Một số thông tin trên tập tin như sau;

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

> file *
:               XML document

> ls -i
 417777   

Tôi đã cố gắng tìm cách sử dụng công tắc inum và sau đó chuyển nó thành rm vì đó dường như là cách dễ dàng nhất để loại bỏ nó. Tuy nhiên, ví dụ đưa ra ở dưới cùng của chuỗi được liên kết dưới đây đối với tôi không thành công. Ví dụ là:

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

Vì vậy, tôi đã thử sử dụng danh sách đường dẫn trước như sau, nhưng nó cũng không hoạt động:

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

Tôi không chắc ký tự không thể in \ 177 là gì hoặc làm thế nào tôi có thể chuyển nó sang một rmlệnh, nhưng tôi thực sự muốn đảm bảo rằng tôi không làm hỏng bất kỳ tệp / thư mục nào khác trong nỗ lực xóa tệp này.


1
\177là ký tự ASCII DEL.
Keith Thompson

9
417777! = 41777
CVn

Điểm tuyệt vời Michael. Đó có lẽ là lý do tại sao lệnh của tôi không bao giờ làm việc.
Ông Moose

@KeithThndry Đây có phải là bát phân không có hàng đầu 0không?
con mèo

1
@cat: Trong bối cảnh này, vâng. Nó theo cú pháp C cho chuỗi ký tự và ký tự.
Keith Thompson

Câu trả lời:


46

Tệp có tên, nhưng nó được tạo từ các ký tự không in được. Nếu bạn sử dụng ksh93, bash, zsh, mksh hoặc FreeBSD sh, bạn có thể thử xóa nó bằng cách chỉ định tên không in được của nó. Trước tiên, đảm bảo rằng tên đó đúng với: ls -ld $'\177' Nếu nó hiển thị đúng tệp, sau đó sử dụng rm:rm $'\177'

Một cách tiếp cận khác (rủi ro hơn một chút) là sử dụng rm -i -- *. Với tùy chọn -i rm yêu cầu xác nhận trước khi xóa một tệp, vì vậy bạn có thể bỏ qua tất cả các tệp bạn muốn giữ ngoại trừ tệp.

Chúc may mắn!


1
Tôi nghi ngờ rằng rm -i *sẽ không làm việc trong trường hợp này; vì các dòng mới, shell sẽ mở rộng *thành một cái gì đó rmkhông thể nhận ra là tên tệp.
Keith Thompson

6
@KeithThndry: Mở rộng Glob trong shell không phải giải thích thêm. Sẽ không có một dòng mới trong tên mở rộng trừ khi nó có một dòng.
Christoffer Hammarström

@ Christoffer Hammarström: Hmm. Tôi sẽ làm một số thí nghiệm và bình luận thêm.
Keith Thompson

@ Christoffer Hammarström: Có một dòng mới trong tên mở rộng vì tên tệp chứa các ký tự dòng mới. Nhưng có vẻ như tôi đã đánh giá thấp bashvà GNU rm. Trên hệ thống của tôi, rm *, rm -i *, và rm Ctrl-V DEL TAB ENTERtất cả các công việc một cách chính xác, thậm chí nếu tên tập tin chứa một ký tự xuống dòng (tôi đã sử dụng "\177foo\nbar\n"). Một số lệnh không xử lý tốt tên tệp như vậy, nhưng các công cụ GNU có vẻ mạnh mẽ; các phiên bản không phải GNU của cùng các công cụ có thể không hoạt động tốt. Trong mọi trường hợp, các thủ thuật khác nhau trong các câu trả lời này rất hữu ích để biết.
Keith Thompson

1
@KeithThndry, bất kỳ trình bao nào cũng sẽ xử lý toàn bộ tệp một cách chính xác, không chỉ Bash và rmkhông bao giờ thực hiện bất kỳ hình thức phân tách từ nào cho dù đó là GNU rmhay không. Shell mở rộng các khối và khi thực thi lệnh được gọi, nó chuyển vào tên tệp kết quả dưới dạng đối số được phân tách bằng null (trong mã C). Điều nguy hiểm là dẫn một danh sách các tập tin vào một cái gì đó sử dụng dòng mới làm dấu phân cách; xem Tại sao lặp đi lặp lại tìm đầu ra thực tiễn xấu?
tự đại diện

23

Đối với những người sử dụng vimchạy nó trong thư mục làm việc hiện tại:

$ vim ./ 

và điều hướng đến tệp bằng các phím mũi tên hoặc j/k. Sau đó nhấn Shift+Dvà xác nhận xóa với y.


Tôi thường cảm thấy sợ vim, nhưng nó hoạt động rất tốt
tofutim

9

Có lẽ có một cách để chuyển tên tệp sang rm, nhưng nếu bạn lo lắng về việc làm hỏng bất cứ điều gì, bạn có thể sử dụng trình quản lý tệp GUI. Emacs đi kèm với chế độ chỉnh sửa thư mục bạn có thể sử dụng nếu bạn đã cài đặt nó:

  1. Mở thư mục trong emacs. Bạn có thể chạy emacs /path/to/folderhoặc mở emacs, nhấn Esc+ xvà chạy dired, điều này sẽ nhắc đường dẫn

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

  2. Di chuyển đến hàng với tệp bạn muốn xóa và nhấn d. Bạn sẽ thấy một Dlề bên trái bên cạnh tệp:

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

  3. Nhấn xđể lưu các thay đổi của bạn. Nó sẽ nhắc để đảm bảo bạn muốn xóa tệp; nhấn y:

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


1
Trông giống như một ý tưởng tuyệt vời, nhưng tôi dường như không thể tìm thấy emacs trên máy này. Có nguy cơ bắt đầu một cuộc chiến thần thánh ... điều này có thể được thực hiện trong vim không?
Ông Moose

2
Đối với những người sử dụng vimchạy nó trong thư mục làm việc hiện tại: vim ./và điều hướng đến tệp bằng các phím mũi tên. Sau đó nhấn Shift+Dvà xác nhận xóa với y.

@hesse Wow. Không phải thứ gì đó tôi mong đợi sẽ vimhỗ trợ
Michael Mrozek

1
@MichaelMrozek đồng ý, nó có tất cả các tính năng mà tôi thỉnh thoảng có xu hướng khám phá.

1
Chế độ @Kevin nyan: nyan
Tim

8

Bạn đã chứng minh file *rằng shell global ( *) có thể chọn tệp này, vì vậy bây giờ chỉ cần thực hiện rmtrên toàn cầu đó.

  • Thay đổi thư mục tập tin.
  • Chạy rm -i *
  • Nhập ncho tất cả các tệp ngoại trừ tệp có tên tệp dường như vô hình

7

Các tập tin thực sự có một tên, nhưng nó được làm bằng các ký tự không in được.

Một phương pháp dễ dàng là dựa vào hoàn thành trình bao: nhấn Tabliên tục cho đến khi tên tập tin lạ lạ được chèn vào. Bạn phải cấu hình shell của mình để xoay vòng giữa các lần hoàn thành có thể:

  • Trong bash, bạn cần phải gọi menu-complete, không bị ràng buộc theo mặc định, hơn là complete, bị ràng buộc Tabtheo mặc định. Ngoài ra, sử dụng Esc *để chèn hoàn thành cho tất cả các tệp và xóa những tệp bạn không muốn xóa khỏi dòng lệnh.
  • Trong zsh, các cài đặt mặc định là tốt; bạn cần phải có setopt auto_menuhoặc setopt menu_completethiết lập.

Nếu việc hoàn thành không hữu ích trong trình bao của bạn, bạn có thể gọi rm -i -- *và trả lời không có gì ngoại trừ tập tin cụ thể này. Nếu tên tệp không bắt đầu bằng ký tự có thể in, bạn có thể giới hạn các kết quả khớp với các tệp có ký tự đầu tiên không nằm trong một tập hợp các ký tự có thể in:

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

(Coi chừng nếu mẫu của bạn có thể khớp với một tệp được gọi -f, tệp này rmsẽ coi là một tùy chọn.)

Một phương pháp khác là gọi ls -iđể tìm inode của tệp (một inode xác định duy nhất một tệp trên một hệ thống tệp nhất định), sau đó find -inumđể hoạt động trên tệp cụ thể đó. Phương pháp này chủ yếu hữu ích khi thư mục chứa rất nhiều tệp.

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

Nếu bạn findkhông có -deletetùy chọn, hãy gọi rm:

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

(Vâng, tôi biết rằng hầu hết những điều này đã được đăng. Nhưng những câu trả lời với thông tin liên quan đang khiến việc này trở nên phức tạp hơn mức cần thiết.)


4

Hãy thử sử dụng echo -eđể có được nhân vật \177, sau đó xargschuyển nó đến rm. echokhông thực hiện thoát số thập phân, vì vậy chuyển đổi thành hex: Hóa ra 177là bát phân; echoyêu cầu một \0(bằng chữ, không phải byte rỗng) trước:

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

Bạn đang nói rằng \ xb1 \ 0 là đại diện hex của \ 177?
Ông Moose

@MrMoose \xb1là số thập phân 177, \0kết thúc null và -0yêu xargscầu lấy tên kết thúc null thay vì tên kết thúc dòng mới.
Kevin

Tôi đang sử dụng bash trên SunOS và khi tôi thử lệnh của bạn, tôi nhận được xargs: tùy chọn bất hợp pháp - 0. Tôi đã xem trang người đàn ông và không thể thấy tùy chọn chấm dứt null. Tôi đã quản lý để có được một sửa chữa cho vấn đề bây giờ mặc dù. Xem câu trả lời được đánh dấu là câu trả lời.
Ông Moose

Của bạn echo, như hiện tại, sẽ gửi 2 tên tệp cho xargs, và sau đó đến rm... tên tệp thứ hai là \n.. Điều này dẫn đến một lỗi hoặc xóa một tệp có tên đó ('\ n')
Peter. Ô

@perer Vâng, tôi mới nhận thấy điều đó. Tôi đã thêm -nđể thoát khỏi dòng mới.
Kevin

3

Tôi có thể chỉ là về đảm bảo với bạn rằng file không có tên. Nó chỉ là một cái tên có chứa các ký tự không in được.

Nếu rmkhông làm việc, sau đó sử dụng đầu ra của findcác -inumtùy chọn như một đối số rmkhông có khả năng để giúp đỡ; nó sẽ vượt qua cùng một lý lẽ rm, với cùng một vấn đề.

Các tập tin là duy nhất trong thư mục đó, phải không?

Điều đầu tiên tôi muốn thử là cdvào thư mục, sau đó nhập rm ./, sau đó nhấn phím Tab. Điều này sẽ mở rộng đối số thành tên thực của tệp và trước đó ./sẽ ngăn không cho rmdiễn giải đối số là tên khác với tên tệp.

Một giải pháp khác là vào cdthư mục mẹ, sau đó sử dụng rm -r(hoặc, nếu cần, rm -rf) trên thư mục. Điều đó sẽ loại bỏ thư mục và tất cả nội dung của nó, bất kể tên. Sau đó, bạn có thể sử dụng mkdirđể tạo lại thư mục (và có lẽ chmodđể khôi phục quyền của nó).

BIÊN TẬP :

Nhìn lại ls -lbđầu ra của bạn , tôi nghĩ rằng tên tệp bắt đầu bằng ký tự ASCII DEL(xấu không phải không gây tử vong) chứa một hoặc nhiều ký tự dòng mới (thực sự xấu). Theo như tôi có thể nói, rmlệnh không thể diễn giải một dòng mới như là một phần của tên tệp.

Nhưng unlink()cuộc gọi hệ thống có thể. Đây là tập lệnh Perl mà tôi đã tập hợp lại, nó sẽ lặp qua các tệp trong thư mục hiện tại và hỏi bạn từng cái xem bạn có muốn xóa nó không. Nó không sử dụng một lệnh bên ngoài như rmđể loại bỏ các tệp, do đó, nó sẽ có thể xử lý bất kỳ ký tự vui nhộn nào mà hệ thống tệp hỗ trợ (bất kỳ thứ gì khác ngoài ASCII NUL/).

Làm rm -rhoặc rm -rftrên thư mục chứa vẫn hoạt động, nhưng nếu bạn chỉ muốn xóa một tệp duy nhất, bạn có thể thử điều này.

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

(Một giải pháp khác, nếu có các tệp khác trong thư mục mà bạn muốn giữ, là di chuyển tất cả các tệp khác vào một thư mục tạm thời, sau đó nuke và tạo lại thư mục và di chuyển các tệp khác trở lại.)

(Ồ, và bất cứ điều gì bạn đã làm để tạo tệp đó, hãy cố gắng không làm lại!)


1

Nếu bạn có thể tìm thấy chính xác tệp đó bằng findlệnh, thì bạn có thể sử dụng -deletevị ngữ. Chỉ cần cẩn thận và tạo -deletemột tham số cuối cùng của lệnh find hoặc nó sẽ làm tổn thương rất nhiều ...


1

Bạn thân thiết. Từng bước, đây là cách xóa tệp bằng số inode.

Đầu tiên, tìm số inode của tệp bạn muốn, sử dụng ls -li. Số inode sẽ ở cột đầu ra.

Ví dụ:

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

Trong trường hợp này, số inode là 311010

Sử dụng findđể tìm tệp theo số inode.

find . -inum 311010 

Đảm bảo rằng findchỉ trả về tên của tệp bạn muốn xóa. Ví dụ:

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

Khi bạn chắc chắn rằng findđang tìm đúng tệp, sau đó chuyển -deletetham số cho find. Nó sẽ xóa các tập tin cho bạn.

find . -inum 311010 -delete

0

Các câu trả lời khác là tuyệt vời và sẽ hoạt động trong hầu hết các môi trường.

Nhưng, nếu bạn có gui đang chạy, chỉ cần mở thư mục bằng nautilus, cá heo, konqueror hoặc trình quản lý tệp yêu thích của bạn và bạn sẽ có thể dễ dàng xem và xóa bất kỳ tệp nào có tên không hợp tác với một vài lần nhấp chuột .

Nếu bạn không phải là người dùng emacs hoặc vim thông thường (như được nêu trong một số câu trả lời khác), đây có thể là cách dễ nhất để đi.


0

Có một vấn đề tương tự với một tệp có tên "\ 033" (ký tự "Thoát" thực tế).

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

Ở trên sẽ nhắc bạn xóa các tệp trong thư mục hiện tại không bắt đầu bằng một chữ cái hoặc số.


0

Thay vào đó, bạn có thể đổi tên thư mục hiện tại thành DirX_OLD, tạo một thư mục mới với tên DirXvà di chuyển tất cả các tệp cần thiết từ DirX_OLDsang DirX. Sau khi sao chép các tập tin bạn có thể xóaDirX_OLD


0

Chỉ trong trường hợp nó giúp bất cứ ai tôi sẽ thêm giá trị hai xu của tôi. Tôi đã có thể lấy (các) tên tệp bằng cách sử dụng statký tự đại diện như thế này:

stat -c %N *

Đầu ra:

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

Sau đó, tôi có thể sử dụng các chuỗi trích dẫn ANSI C (như được sử dụng trong câu trả lời được chấp nhận) để truy cập các tệp:

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

0

Mỗi tập tin có một tên, bạn chỉ cần tìm chính xác.

Tôi sẽ sử dụng tệp này làm ví dụ:

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

Những tập tin đó sẽ hiển thị như ?bình thường ls:

$ ls
??  ?  ?002  a  abc  b

Nhưng nếu bạn lscho phép -Qtùy chọn thì rõ ràng tên tệp thực là gì:

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

đó là các số inode và tên "Trích dẫn" trong 1cột của các tệp trong pwd.

Đó là sử dụng khả năng của vỏ (POSIX) để sử dụng các mở rộng (globalbing):

Để có tên với bất kỳ ký tự không in:

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

Và để liệt kê các tệp có thể chỉ có các ký tự không in:

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

Sau đó, để chọn lọc ( -itùy chọn (tương tác)) loại bỏ chúng sử dụng:

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

Bạn chỉ cần chọn cái nào cần xóa bằng cách trả lời ycâu hỏi trên.


0

Nếu bạn có một bash với tự động hoàn thành, điều này có thể làm việc cho bạn. Tôi gõ ký tự được hiển thị trong danh sách thư mục. Sau đó, tôi kích hoạt tự động hoàn thành và đổi tên thứ đó thành thứ có thể in được.

Đây là những gì làm việc cho tôi:

$ 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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.