ฉันจะลบไฟล์ที่ชื่อไฟล์มีอักขระที่ไม่ได้พิมพ์ได้อย่างไร


46

ฉันพยายามสร้างไฟล์ที่ดูเหมือนจะไม่มีชื่อไฟล์ ฉันพบข้อมูลบางอย่างเกี่ยวกับวิธีรับรายละเอียดเพิ่มเติมของไฟล์ในเธรดต่อไปนี้

อย่างไรก็ตามฉันลองใช้คำแนะนำที่ปรากฏและไม่สามารถลบไฟล์ได้ ฉันไม่แน่ใจว่าสิ่งที่ฉันทำเพื่อสร้างมัน แต่มันเกิดขึ้นขณะพยายามคัดลอกไฟล์ xml

ข้อมูลบางอย่างเกี่ยวกับไฟล์มีดังนี้

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

> file *
:               XML document

> ls -i
 417777   

ฉันพยายามค้นหาโดยใช้สวิตช์ inum จากนั้นก็เป่าไปที่ rm เพราะดูเหมือนจะเป็นวิธีที่ไม่น่าเชื่อถือที่สุดในการกำจัดมัน อย่างไรก็ตามตัวอย่างที่ให้ไว้ที่ด้านล่างของเธรดที่ลิงก์ด้านล่างล้มเหลวสำหรับฉัน ตัวอย่างคือ:

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

ดังนั้นฉันจึงลองใช้รายการเส้นทางก่อนเช่นนี้ แต่ไม่ได้ผล:

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

ฉันไม่แน่ใจว่าอักขระที่ไม่สามารถพิมพ์ได้ \ 177 นั้นคืออะไรหรือฉันจะส่งต่อไปยังrmคำสั่งได้อย่างไร แต่ฉันต้องการให้แน่ใจว่าฉันจะไม่ทำให้ไฟล์ / ไดเรกทอรีอื่น ๆ เสียหายเมื่อพยายามลบไฟล์นี้


1
\177เป็นแอสกีDELอักขระ
Keith Thompson

9
417777! = 41777
CVN

จุดยอดเยี่ยมของไมเคิล นั่นอาจเป็นสาเหตุที่คำสั่งของฉันไม่ทำงาน
Mr Moose

@ KeithThompson มันเป็นเลขฐานแปดโดยไม่ต้องนำ0?
แมว

1
@cat: ในบริบทนี้ใช่ มันเป็นไปตามไวยากรณ์ C สำหรับสตริงและตัวอักษรตัวอักษร
Keith Thompson

คำตอบ:


46

ไฟล์นี้มีชื่อ แต่มันทำจากอักขระที่ไม่สามารถพิมพ์ได้ หากคุณใช้ ksh93, bash, zsh, mksh หรือ FreeBSD sh คุณสามารถลองลบมันได้โดยระบุชื่อที่ไม่สามารถพิมพ์ได้ ก่อนอื่นให้แน่ใจว่าชื่อนั้นถูกต้องด้วย: ls -ld $'\177' หากมันแสดงไฟล์ที่ถูกต้องให้ใช้ rm:rm $'\177'

อื่น ๆ (บิตความเสี่ยงมากขึ้น) rm -i -- *วิธีการคือการใช้งาน ด้วยอ็อพชัน -i rm ต้องการการยืนยันก่อนที่จะลบไฟล์ดังนั้นคุณสามารถข้ามไฟล์ทั้งหมดที่คุณต้องการเก็บไว้ แต่ไฟล์เดียว

โชคดี!


1
ฉันสงสัยว่าrm -i *จะไม่ทำงานในกรณีนี้ เนื่องจากการขึ้นบรรทัดใหม่เชลล์จะขยาย*ไปยังสิ่งที่rmไม่รู้จักเป็นชื่อไฟล์
Keith Thompson

6
@ KeithThompson: การขยายตัวของ Glob ในเชลล์นั้นไม่ได้มีการตีความเพิ่มเติม จะไม่มีการขึ้นบรรทัดใหม่ในชื่อที่ขยายยกเว้นว่ามีหนึ่งบรรทัด
Christoffer Hammarström

@ ChristofferHammarström: อืม ฉันจะทำการทดลองและแสดงความคิดเห็นเพิ่มเติม
Keith Thompson

@ ChristofferHammarström: มีการขึ้นบรรทัดใหม่ในชื่อที่ขยายเนื่องจากชื่อไฟล์มีอักขระขึ้นบรรทัดใหม่ แต่ดูเหมือนว่าผมเคยประเมินbashและ rmGNU ในระบบของฉันrm *, rm -i *และrm Ctrl-V DEL TAB ENTERทำงานได้อย่างถูกต้องแม้ว่าชื่อไฟล์ที่มีตัวอักษรขึ้นบรรทัดใหม่ (ผมใช้"\177foo\nbar\n") คำสั่งบางคำไม่สามารถจัดการชื่อไฟล์ดังกล่าวได้ดี แต่เครื่องมือของ GNU นั้นดูแข็งแรง เครื่องมือเดียวกันรุ่นที่ไม่ใช่ GNU อาจทำงานได้ไม่ดีนัก ไม่ว่าในกรณีใดเทคนิคต่าง ๆ ในคำตอบเหล่านี้มีประโยชน์ที่จะรู้
Keith Thompson

1
@ KeithThompson เชลล์ใด ๆ จะจัดการกับไฟล์ได้อย่างถูกต้องไม่เพียง แต่ Bash และrmไม่ทำการแยกคำในรูปแบบใด ๆ ไม่ว่าจะเป็น GNU rmหรือไม่ก็ตาม เชลล์ขยาย globs และเมื่อเรียกใช้งานคำสั่งที่เรียกใช้จะส่งผ่านชื่อไฟล์ที่ได้เป็นอาร์กิวเมนต์ที่คั่นด้วย null (ในรหัส C) สิ่งที่อันตรายคือไปป์ลิสต์ของไฟล์กับสิ่งที่ใช้การขึ้นบรรทัดใหม่เป็นตัวคั่น ดูเหตุใดจึงวนซ้ำการฝึกที่ไม่ดีของเอาท์พุท
สัญลักษณ์แทน

23

สำหรับผู้ที่ใช้vimเรียกใช้ในไดเรกทอรีการทำงานปัจจุบัน:

$ vim ./ 

j/kและนำทางไปยังไฟล์ที่มีปุ่มลูกศรหรือ จากนั้นกดและการลบยืนยันด้วยShift+Dy


ฉันมักจะกลัวกลุ่ม แต่ทำงานได้ดีจริงๆ
tofutim

9

อาจมีวิธีส่งชื่อไฟล์ให้rmแต่ถ้าคุณกังวลว่าจะทำอะไรผิดพลาดคุณสามารถใช้ตัวจัดการไฟล์ GUI ได้ Emacs มาพร้อมกับโหมดแก้ไขไดเรกทอรีที่คุณสามารถใช้ได้หากติดตั้งไว้แล้ว:

  1. emacsเปิดโฟลเดอร์ใน คุณสามารถเรียกใช้emacs /path/to/folderหรือเปิด emacs กดEsc+ xและเรียกใช้diredซึ่งจะแจ้งให้เส้นทาง

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

  2. dย้ายไปแถวที่มีไฟล์ที่คุณต้องการลบและกด คุณควรเห็นDระยะขอบซ้ายถัดจากไฟล์:

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

  3. กดxเพื่อบันทึกการเปลี่ยนแปลงของคุณ มันจะพร้อมท์เพื่อให้แน่ใจว่าคุณต้องการลบไฟล์ กดy:

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


1
ดูเหมือนความคิดที่ดี แต่ฉันไม่สามารถหา emacs บนเครื่องนี้ได้ เมื่อมีความเสี่ยงในการเริ่มสงครามศักดิ์สิทธิ์ ... สิ่งนี้สามารถทำได้เป็นกลุ่ม?
Mr Moose

2
สำหรับผู้ที่ใช้vimเรียกใช้ในไดเรกทอรีการทำงานปัจจุบัน: vim ./และนำทางไปยังไฟล์ด้วยปุ่มลูกศร จากนั้นกดและการลบยืนยันด้วยShift+D y

@hesse Wow ไม่ใช่สิ่งที่ฉันคาดหวังว่าvimจะได้รับการสนับสนุน
Michael Mrozek

1
@MichaelMrozek ตกลงมีคุณสมบัติเหล่านี้ทั้งหมดที่ฉันมักจะค้นพบเป็นครั้งคราว


8

คุณได้แสดงให้เห็นแล้วfile *ว่า shell glob ( *) สามารถรับไฟล์นี้ได้ดังนั้นตอนนี้เพียงแค่ทำrmกับ glob นั้น

  • เปลี่ยนเป็นไดเร็กทอรีที่ไฟล์นั้นอยู่
  • วิ่ง rm -i *
  • ป้อนnไฟล์ทั้งหมดยกเว้นไฟล์ที่มีชื่อไฟล์ที่มองไม่เห็น

7

ไฟล์มีชื่อจริง แต่มันทำจากอักขระที่ไม่สามารถพิมพ์ได้

วิธีที่ง่ายคือการพึ่งพาการทำให้เชลล์สมบูรณ์: กดTabซ้ำ ๆ จนกระทั่งชื่อไฟล์“ แปลก” ถูกใส่เข้าไป คุณต้องกำหนดค่าเปลือกของคุณให้วนไปมาระหว่างความสำเร็จที่เป็นไปได้:

  • ใน bash คุณต้องเรียกใช้menu-completeซึ่งไม่ได้ถูกผูกมัดโดยค่าเริ่มต้นแทนที่จะcompleteเป็นซึ่งจะผูกไว้กับTabค่าเริ่มต้น หรือใช้Esc *เพื่อแทรกไฟล์ที่สมบูรณ์สำหรับไฟล์ทั้งหมดและลบไฟล์ที่คุณไม่ต้องการลบออกจากบรรทัดคำสั่ง
  • ใน zsh การตั้งค่าเริ่มต้นนั้นใช้ได้ คุณต้องมีsetopt auto_menuหรือsetopt menu_completeตั้งค่า

หากการทำให้สมบูรณ์ไม่เป็นประโยชน์ในเชลล์คุณสามารถโทรrm -i -- *และตอบ“ ไม่” ยกเว้นไฟล์นี้โดยเฉพาะ หากชื่อไฟล์ไม่ได้ขึ้นต้นด้วยอักขระที่พิมพ์ได้คุณสามารถ จำกัด การจับคู่กับไฟล์ที่อักขระตัวแรกไม่อยู่ในชุดของอักขระที่พิมพ์ได้:

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

(ระวังหากรูปแบบของคุณอาจตรงกับไฟล์ที่เรียก-fซึ่งrmจะถือว่าเป็นตัวเลือก)

อีกวิธีหนึ่งคือการเรียกls -iเพื่อค้นหา inode ของไฟล์ (inode จะระบุไฟล์ในระบบไฟล์ที่กำหนดfind -inumโดยเฉพาะ) จากนั้นดำเนินการกับไฟล์นั้น วิธีนี้มีประโยชน์ส่วนใหญ่เมื่อไดเรกทอรีมีไฟล์จำนวนมาก

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

หากคุณfindไม่มี-deleteตัวเลือกให้โทรrm:

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

(ใช่ฉันรู้ว่าส่วนใหญ่นี้ได้รับการโพสต์แล้ว แต่คำตอบที่มีข้อมูลที่เกี่ยวข้องทำให้สิ่งนี้ซับซ้อนเกินกว่าที่ควรจะเป็น)


4

ลองใช้echo -eจะได้รับตัวละคร\177แล้วจะผ่านมันไปxargs ไม่ต้องใช้ทศนิยมเพื่อแปลงเป็นเลขฐานสิบหก:กลายเป็น is octal; ต้องมี(ตัวอักษรไม่ใช่ไบต์ว่าง) ก่อน:rmecho177echo\0

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

คุณกำลังบอกว่า \ xb1 \ 0 เป็นเลขฐานสิบหกของ \ 177?
Mr Moose

@MrMoose \xb1เป็นทศนิยม177ซึ่ง\0จะยกเลิกค่า null และ-0บอกxargsให้ใช้ชื่อที่ลงท้ายด้วย null แทนชื่อที่ยกเลิกการขึ้นบรรทัดใหม่
Kevin

ฉันใช้ทุบตีกับ SunOS และเมื่อฉันลองใช้คำสั่งของคุณฉันได้ xargs: ตัวเลือกที่ผิดกฎหมาย - 0 ฉันดูหน้า man และไม่เห็นตัวเลือกสำหรับการยกเลิกแบบ null ฉันจัดการเพื่อแก้ไขปัญหาในขณะนี้แม้ว่า ดูคำตอบที่ทำเครื่องหมายว่าเป็นคำตอบ
Mr Moose

ของคุณechoเป็นตัวส่ง2ชื่อไฟล์ที่จะ xargs และจากนั้นก็ไปrm... ชื่อไฟล์ที่สองคือ\n.. ผลการนี้ทั้งในข้อผิดพลาดหรือลบไฟล์ชื่อนั้น ( '\ n')
ปีเตอร์ O

@ คนที่ใช่ฉันเพิ่งสังเกตเห็นว่า ฉันเพิ่ม-nเพื่อกำจัดบรรทัดใหม่
เควิน

3

ฉันสามารถรับประกันคุณได้ว่าไฟล์จะมีชื่อ มันเป็นชื่อที่มีอักขระที่ไม่สามารถพิมพ์ได้

ถ้าrmไม่ได้ทำงานแล้วใช้การส่งออกของfindด้วย-inumตัวเลือกที่เป็นอาร์กิวเมนต์ที่จะrmไม่น่าจะช่วยเหลือ มันจะผ่านการโต้แย้งrmเดียวกันกับปัญหาเดียวกัน

ไฟล์เป็นไฟล์เดียวในไดเรกทอรีนั้นใช่ไหม

สิ่งแรกที่ฉันจะลองคือcdเข้าไปในไดเรกทอรีจากนั้นพิมพ์rm ./จากนั้นกดปุ่ม Tab สิ่งนี้ควรขยายอาร์กิวเมนต์ให้เป็นชื่อจริงของไฟล์และสิ่งที่./ควรทำก่อนหน้านี้จะป้องกันrmการตีความอาร์กิวเมนต์เป็นสิ่งอื่นที่ไม่ใช่ชื่อไฟล์

อีกวิธีหนึ่งคือไปcdที่ไดเรกทอรีหลักจากนั้นใช้rm -r(หรือหากจำเป็นrm -rf) ในไดเรกทอรี ที่ควรลบไดเรกทอรีและเนื้อหาทั้งหมดโดยไม่คำนึงถึงชื่อ จากนั้นคุณสามารถใช้mkdirเพื่อสร้างไดเรกทอรีใหม่ (และอาจใช้chmodเพื่อเรียกคืนสิทธิ์)

แก้ไข:

เมื่อดูls -lbผลลัพธ์ของคุณอีกครั้งฉันคิดว่าชื่อไฟล์เริ่มต้นด้วยอักขระ ASCII DEL(ซึ่งไม่เลวไม่ร้ายแรง) และมีอักขระขึ้นบรรทัดใหม่อย่างน้อยหนึ่งตัว (ซึ่งแย่มาก) เท่าที่ฉันสามารถบอกได้rmคำสั่งไม่สามารถตีความบรรทัดใหม่เป็นส่วนหนึ่งของชื่อไฟล์

แต่การunlink()เรียกระบบสามารถ ต่อไปนี้เป็นสคริปต์ Perl ที่ฉันรวบรวมไว้ซึ่งจะวนซ้ำไฟล์ต่างๆในไดเรกทอรีปัจจุบันและถามคุณว่าจะลบออกหรือไม่ มันไม่ได้ใช้คำสั่งภายนอกที่ต้องการrmลบไฟล์ดังนั้นมันควรจะสามารถจัดการกับตัวละครตลก ๆ ที่ระบบไฟล์รองรับ (นอกเหนือจาก ASCII NULและ/)

การทำrm -rหรือrm -rfในไดเรกทอรีที่มีควรจะยังคงทำงาน แต่ถ้าคุณเพียงแค่ต้องการลบไฟล์เดียวคุณสามารถลองนี้

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

(โซลูชันอื่นหากมีไฟล์อื่นในไดเรกทอรีที่คุณต้องการเก็บไว้คือย้ายไฟล์อื่น ๆ ทั้งหมดไปยังไดเรกทอรีชั่วคราวจากนั้นให้ nuke และสร้างไดเรกทอรีขึ้นใหม่และย้ายไฟล์อื่นกลับคืน)

(โอ้และทุกสิ่งที่คุณทำเพื่อสร้างไฟล์นั้นลองไม่ทำอีกครั้ง!)


1

หากคุณสามารถหาว่าแฟ้มที่ใช้findคำสั่งแล้วคุณสามารถใช้-deleteคำกริยา แค่ระวังและสร้าง-deleteพารามิเตอร์สุดท้ายของคำสั่ง find ไม่เช่นนั้นมันจะเจ็บมาก ...


1

คุณอยู่ใกล้ ทีละขั้นตอนนี่คือวิธีการลบไฟล์โดยหมายเลข inode

แรกพบจำนวน inode ls -liของไฟล์ที่คุณต้องการใช้ หมายเลขไอโหนดจะอยู่ในคอลัมน์แรกของเอาต์พุต

ตัวอย่างเช่น:

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

ในกรณีนี้หมายเลขไอโหนดคือ 311010

ใช้findเพื่อค้นหาไฟล์ตามหมายเลข inode

find . -inum 311010 

ตรวจสอบให้แน่ใจว่าfindส่งคืนชื่อไฟล์ที่คุณต้องการลบเท่านั้น ตัวอย่างเช่น:

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

เมื่อคุณแน่ใจว่าfindจะหาไฟล์ขวาแล้วผ่านพารามิเตอร์-delete findมันจะลบไฟล์ให้คุณ

find . -inum 311010 -delete

0

คำตอบอื่น ๆ นั้นยอดเยี่ยมและจะใช้ได้ในทุกสภาพแวดล้อม

แต่ถ้าคุณใช้งาน gui ให้เปิดไดเรกทอรีใน nautilus, dolphin, konqueror หรือตัวจัดการไฟล์โปรดของคุณและคุณควรจะสามารถดูและลบไฟล์ใด ๆ ที่มีชื่อที่ไม่ร่วมมือได้อย่างง่ายดาย .

หากคุณไม่ใช่ผู้ใช้ emacs หรือ vim ทั่วไป (ดังที่แสดงในคำตอบอื่น ๆ ) นี่อาจเป็นวิธีที่ง่ายที่สุด


0

มีปัญหาคล้ายกันกับไฟล์ชื่อ "\ 033" (ตัวอักษร "Escape" จริง)

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

ด้านบนจะแจ้งให้คุณลบไฟล์ในไดเรกทอรีปัจจุบันที่ไม่ได้ขึ้นต้นด้วยตัวอักษรหรือตัวเลข


0

แต่คุณสามารถเปลี่ยนชื่อไดเรกทอรีปัจจุบันเพื่อDirX_OLDสร้างไดเรกทอรีใหม่ที่มีชื่อDirXและย้ายไฟล์ทั้งหมดที่จำเป็นจากการDirX_OLD DirXหลังจากคัดลอกไฟล์คุณสามารถลบDirX_OLD


0

ในกรณีที่ช่วยใครก็ตามฉันจะเพิ่มสองเซ็นต์ของฉันมีค่า ฉันสามารถรับชื่อไฟล์ที่ใช้statในไวลด์การ์ดดังนี้:

stat -c %N *

เอาท์พุท:

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

จากนั้นฉันสามารถใช้สตริงที่ยกมา ANSI C (ตามที่ใช้ในคำตอบที่ยอมรับ) เพื่อเข้าถึงไฟล์:

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

0

ทุกไฟล์มีชื่อคุณเพียงแค่ต้องค้นหาว่าสิ่งใด

ฉันจะใช้ไฟล์นี้เป็นตัวอย่าง:

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

ไฟล์เหล่านั้นจะแสดงตาม?ปกติls:

$ ls
??  ?  ?002  a  abc  b

แต่ถ้าคุณlsอนุญาตให้-Qตัวเลือกมันควรจะชัดเจนว่าชื่อไฟล์จริงคืออะไร:

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

นี่คือหมายเลขไอโหนดและชื่อ "ที่ยกมา" ใน1คอลัมน์ของไฟล์ใน pwd

นั่นคือการใช้ hability ของเชลล์ (POSIX) เพื่อใช้การขยาย (กลม):

ในการมีชื่อที่มีอักขระที่ไม่ได้พิมพ์:

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

และในรายการไฟล์ที่อาจมีเฉพาะอักขระที่ไม่ได้พิมพ์:

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

จากนั้นให้เลือก ( -iตัวเลือก (โต้ตอบ)) เพื่อลบออกใช้:

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

คุณเพียงแค่ต้องเลือกว่าจะลบรายการใดโดยตอบyคำถามข้างต้น


0

หากคุณมี bash พร้อมการเติมข้อความอัตโนมัติสิ่งนี้อาจใช้ได้กับคุณ ฉันพิมพ์อักขระที่แสดงในรายการไดเรกทอรี จากนั้นฉันก็เรียกการเติมข้อความอัตโนมัติและเปลี่ยนชื่อสิ่งเป็นสิ่งที่พิมพ์ได้

นี่คือสิ่งที่ทำงานให้ฉัน:

$ 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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.