Як я можу видалити файл, ім'я якого має символи, що не друкуються


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символом ASCII .
Кіт Томпсон

9
! 417777 = 41777
CVn

Чудовий момент Майкла. Можливо, тому моя команда ніколи не працювала.
Містер Муз

@KeithThompson Це вісімковий без провідного 0?
кіт

1
@cat: У цьому контексті так. З цього випливає синтаксис C для літеральних рядків та символів.
Кіт Томпсон

Відповіді:


46

У файлі є ім'я, але воно складається з символів, що не друкуються. Якщо ви використовуєте ksh93, bash, zsh, mksh або FreeBSD sh, ви можете спробувати його видалити, вказавши його недруковану назву. Спершу переконайтеся, що ім'я є правильним із: ls -ld $'\177' Якщо він показує потрібний файл, тоді використовуйте rm:rm $'\177'

Ще один (трохи більш ризикований) підхід - використовувати rm -i -- *. За допомогою параметра -i rm вимагає підтвердження перед видаленням файлу, тому ви можете пропустити всі файли, які ви хочете зберегти, крім одного.

Удачі!


1
Я підозрюю, що rm -i *це не спрацювало б у цій справі; через нові рядки оболонка розшириться *до чогось, що rmне буде розпізнаватися як ім'я файлу.
Кіт Томпсон

6
@KeithThompson: Розширення глобальної оболонки в оболонці не підлягає подальшому тлумаченню. Новий рядок у розширеному імені не буде, якщо б він не містив.
Крістофер Хаммарстрем

@ ChristofferHammarström: Хм. Я зроблю кілька експериментів і прокоментую далі.
Кіт Томпсон

@ ChristofferHammarström: У розширеному імені є новий рядок, оскільки ім'я файлу містить символи нового рядка. Але, здається, я недооцінив bashі GNU rm. У моїй системі rm *, rm -i *і rm Ctrl-V DEL TAB ENTERвсі працюють правильно, навіть якщо ім'я файлу містить символ нового рядка (я "\177foo\nbar\n"). Деякі команди не добре обробляють такі імена файлів, але інструменти GNU здаються надійними; версії тих же інструментів, що не є GNU, можуть також не працювати. У будь-якому випадку корисні знати різні хитрощі в цих відповідях.
Кіт Томпсон

1
@KeithThompson, будь-яка оболонка буде правильно обробляти файли, не лише Bash, і rmніколи не розбиває жодної форми слова, будь то GNU rmчи ні. Оболонка розширює глобус і, коли вона виконує закликану команду, передає отримані файли у вигляді розділених на нуль аргументів (у коді С). Що небезпечно - передавати список файлів на те, що використовує нові рядки як роздільники; див. Чому зациклість на поганій практиці пошуку результатів пошуку?
Wildcard

23

Для тих, хто використовує, vimзапустіть його у поточному робочому каталозі:

$ vim ./ 

і перейдіть до файла за допомогою клавіш зі стрілками або j/k. Потім натисніть Shift+Dі підтвердьте видалення за допомогою y.


я, як правило, лякаюся vim, але це спрацювало дуже добре
до

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лівому полі поруч із файлом ви повинні побачити a :

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

  3. Натисніть, xщоб зберегти зміни. Буде запропоновано видалити файл; натисніть y:

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


1
Це виглядає як чудова ідея, але я не можу знайти emacs на цій машині. Загрожуючи розпочати священну війну ... чи можна це зробити в vim?
Містер Муз

2
Для тих, хто використовує, vimзапустіть його у поточному робочому каталозі: vim ./та перейдіть до файла за допомогою клавіш зі стрілками. Потім натисніть Shift+Dі підтвердьте видалення за допомогою y.

@hesse Wow Не те, що я б сподівався vimпідтримати
Майкл Мрозек

1
@MichaelMrozek погодився, він має всі ці особливості, які я професійно прагну виявити.

1
Режим @Kevin nyan
Тім

8

Ви вже продемонстрували, file *що оболонка glob ( *) здатна забрати цей файл, тому тепер просто зробіть rmцей глобус.

  • Перейдіть до каталогу, у якому знаходиться файл.
  • Біжи 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щоб передати його rm. echoне приймає десяткових вхідних знаків, тому перетворять у шістнадцятковий: Виходить 177восьмеричний; echoвимагає \0(буквальний, а не нульовий байт) перед:

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

Ви говорите, що \ xb1 \ 0 - це шістнадцяткове подання \ 177?
Містер Муз

@MrMoose \xb1є десятковою 177, недійсно \0закінчує її і -0каже xargsприймати ім'я, що закінчується нулем , а не нове , що закінчується рядком.
Кевін

Я використовую bash на SunOS, і коли я спробував вашу команду, я отримав xargs: незаконний варіант - 0. Я переглянув сторінку man і не побачив опції для скасування нуля. Однак мені вдалося знайти виправлення проблеми. Дивіться відповідь, позначений як відповідь.
Містер Муз

Ваш echo, як є, надсилає 2 імені файлів до xargs, а потім - до rm... другого імені файлу \n.. Це призводить до помилки, або до видалення файлу з таким іменем ('\ n')
Peter. O

@perer Так, я щойно це помітив. Я додав, -nщоб позбутися нового рядка.
Кевін

3

Я можу тільки про гарантію, що файл дійсно є ім'я. Це просто буває ім'я, яке містить символи, що не друкуються.

Якщо rmне вийшло, то використання результату findз -inumпараметром як аргументу rmне допоможе; це просто передасть той же аргумент rm, з тією ж проблемою.

Файл єдиний у цьому каталозі, правда?

Перше, що я спробую, - це cdувійти в каталог, потім ввести rm ./, а потім натиснути клавішу Tab. Це повинно розширити аргумент на власне ім'я файлу, а попередній ./повинен запобігти rmінтерпретації аргументу як щось інше, ніж ім'я файлу.

Інше рішення полягає в тому, щоб cdмати батьківський каталог, а потім використовувати rm -r(або, якщо потрібно, rm -rf) в каталозі. Це повинно видалити каталог та весь його вміст, незалежно від назви. Потім ви можете mkdirвідтворити каталог (і, можливо, chmodвідновити його дозволи).

Редагувати:

ls -lbЗнову дивлячись на ваш результат, я думаю, що ім'я файлу починається з DELсимволу ASCII (що погано, а не фатально) і містить один або кілька символів нового рядка (що насправді погано). Наскільки я можу сказати, 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;
}

(Іншим рішенням, якщо в каталозі є інші файли, які ви хочете зберегти, є переміщення всіх інших файлів у тимчасовий каталог, а потім видалення та відновлення каталогу та переміщення інших файлів назад.)

(О, і що б ви не зробили для створення цього файлу, намагайтеся не робити цього знову!)


1

Якщо ви можете знайти саме цей файл за допомогою findкоманди, ви можете використовувати -deleteпредикат. Просто будьте обережні, і зробіть -deleteостанній параметр команди пошуку, або це зашкодить сильно ...


1

Ви близькі. Крок за кроком, ось як видалити файл за номером inode.

Спочатку знайдіть номер inode потрібного файлу, використовуючи ls -li. Число inode буде в першому стовпці виводу.

Наприклад:

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

У цьому випадку номер inode - 311010

Використовуйте findдля пошуку файлу за номером inode.

find . -inum 311010 

Переконайтеся, що findповертається лише ім'я файлу, який ви хочете видалити. Наприклад:

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

Після того, як ви впевнені, що findзнаходите потрібний файл, передавайте -deleteпараметр find. Він видалить файл для вас.

find . -inum 311010 -delete

0

Інші відповіді чудові і працюватимуть майже в усіх середовищах.

Але, якщо у вас працює Gui, просто відкрийте каталог у наутилусі, дельфіні, 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"

це числа inode та "Quoted" у 1стовпці файлів у pwd.

Тобто використовується здатність оболонки (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

Якщо у вас баш з автозавершенням, це може працювати для вас. Я набрав символ, який був показаний у списку каталогів. Потім я запустив автозаповнення і перейменував річ на щось для друку.

Ось що для мене спрацювало:

$ 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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.