Работа с «плохими» файлами в командной строке в Linux

    При работе в командной строке администраторы часто сталкиваются с необходимостью что-то сделать с определенным файлом: удалить, переместить, скопировать. При выполнении подобных задач зачастую приходится обращаться к файлам по имени, что может быть затруднительно, поскольку в именах файлов могут встречаться самые разные символы. Даже те, которых нет на клавиатуре. В этом плане работу может облегчить файловый менеджер, в котором файл можно просто выделить и совершить с ним нужное действие. Но для тех, кто привык работать исключительно в командной строке, предлагаются следующие способы.

    В качестве shell-оболочки рассмотрим bash, как самую используемую. А в качестве операции над файлами рассмотрим удаление, как самую деструктивную.

    Ситуации могут быть разными. В текущей директории могут быть файлы, которые нужно удалить вместе с теми, которые нужно оставить. Имена у них могут быть самыми разными. Причем первые от последних могут отличаться только одним каким-нибудь заковыристым символом.


    В названии файла есть служебный символ bash


    Самый простой случай. Для удаления файлов, содержащих в своем названии служебные символы вроде пробелов, кавычек, двойных кавычек, звездочек, обратные кавычки и др. можно заэкранировать обратным слешем или использовать одинарные кавычки:

    $ rm -f my\:file\ name
    $ rm -f 'my file with white:spaces:and:colons'
    $ rm -f \(filename\)
    

    С помощью одинарных кавычек нельзя удалить файл, в названии которого есть одинарная кавычка, даже заэкранировав ее.

    С полным списком служебных символов и механизмом экранирования в bash можно ознакомиться в man bash. Раздел QUOTING.


    Имя файла начинается с дефиса


    Удалить файл, начинающийся с дефиса простым экранированием не получится, и команда rm будет воспринимать дефис, как начало своего аргумента. Решить проблему довольно просто:

    $ rm -f ./-abc
    

    или:

    $ rm -f -- -abc
    


    Удаляем по wildcard


    Если удаление файлов попадает под wildcard-маску, то можно удалить всю группу файлов:

    $ rm -f *.jpg
    


    Файлы с управляющим символом в названии


    В названии файла может встречаться управляющий ASCII-символ, такой как перевод строки (\n), табуляция (\t), backspace (\b). Это символы с ASCII-кодами менее 0x20, а также символы DELETE и ESC. Для удаления таких файлов подходит конструкция:

    $ rm -f $'any\nfile'
    $ rm -f $'any\bfile'
    

    Другим способом удаления таких файлов являяется ввод управляющего символа с клавиатуры. Для этого нужно воспользоваться комбинацией клавиш, которая экранирует следующий введенный символ, тем самым запрещая системе обрабатывать его. Как правило, эта комбинация CTRL+V. Точно убедиться в этом можно с помощью команды stty -a, посмотрев на параметр lnext. Удалим файл, содержащий символ ESC:

    $ rm -f any     # жмем CTRL+V, затем ESC
    $ rm -f any^[  # дописываем отсальные символы
    $ rm -f any^[file
    


    Удаление файлов с символами utf8


    Если имя файла содержит символ в кодировке utf8, который мы не можем набрать на клавиатуре, то удалить такой файл можно выделением его мышкой, копированием в буфер обмена и последующей вставкой на ввод команды rm. Главное условие состоит в том, что наш терминал должен работать в кодировке utf8. Кодировка выставляется в настройках терминала. Будь то xterm, putty или брутальный linux tty.

    $ ls -1
    朲晦
    朲晩
    朲晪
    $ rm -f 朲晪
    


    Перекодировка имени файла


    Подозревая, что имя файла находится в кодировке, отличной от кодировки терминала, мы можем выполнить перекодирование всех файлов в текущей директории. В результате файлы с битой кодировкой будут перекодированы, а файлы с ascii-символами изменений не претерпят. Существенный плюс этого способа – приведение всех файлов в читабельный вид.

    $ convmv -fcp1251 -tutf8 *
    

    Как видно, чтобы осуществить правильное перекодирование нужно знать две кодировки: предполагаемую кодировку файла и кодировку нашего терминала. Наиболее трудно распознать предполагаемую кодировку файла по непонятным символам. Есть замечательная табличка

    Также можно воспользоваться сторонними программами, которые попытаются распознать кодировку автоматически. Например, онлайн-декодер Лебедева.

    Если вы встретили такие символы в примонтированном media-носителе или смонтированном разделе Windows, не спешите ничего перекодировать. Возможно, вы просто указали неправильные опции монтирования.

    Автокомплит


    В случае, если в директории название требуемого файла начинается уникально, и это название можно однозначно сформировать автокомплитом, то это довольно простой способ удалить файл:

    $ rm -f icantype_  # жмем TAB 
    $ rm -f icantype_��\ ������.jpg
    


    Удаляем файл через меню выбора


    Если мы дошли сюда, дело плохо. Попробуем удалить конкретный файл, составив для этого меню выбора. В итоге, все что нам останется сделать – это выбрать нужный пункт меню вместо ввода имени файла. Для этого нам нужно запрограммировать действие, которое будет происходить с файлом или файлами после ввода нами нужных пунктов меню.

    $ select i in *; do rm -f $i; done
    1) file.zip  3) ??? ???.doc                5) 朲晩
    2) ?? ??.jpg                       4) 朲晦
    #? 2
    #? ^C
    


    Удаление по номеру inode


    Удалить файл можно по его номеру inode. Номер inode уникально идентифицирует файл в файловой системе. Узнать номер inode можно с помощью команды ls, а удалить – с помощью find. Недостаток этого способа, такой же, как у предыдущего. Неудобно, в случае большого числа файлов.

    $ ls -1 -i
    144368 ???.txt
    144363 ??.txt
    $ find . -inum 144368 -delete
    


    Удаление по hex-коду


    И нельзя не упомянуть один суровый метод. Удаление по hex-кодам. Суть такова: мы узнаем hex-коды всех байтов в имени файла, а затем удаляем файл, указывая вместо имени hex-коды.
    
    $ for i in *; do echo -n $i | xxd ; done
    0000000: face c0d0 32a4                           ....2.
    $ rm -f $'\xfa\xce\xc0\xd0\x32\xa4'
    

    Хорошо, все-таки, что на практике такие файлы попадаются нечасто.

    Средняя зарплата в IT

    113 000 ₽/мес.
    Средняя зарплата по всем IT-специализациям на основании 5 771 анкеты, за 2-ое пол. 2020 года Узнать свою зарплату
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 53

    • НЛО прилетело и опубликовало эту надпись здесь
        +5
        Не забывая экранировать всякие $, `, и пр
          +3
          Ага, особенно про "!". Часто натыкался
            +3
            Угу, особенно когда пишешь
            git commit -am "It works!"
            
              0
              Ага. Или -am "It works!!" :)
              0
              В принципе, если не пользоваться history expansion, то можно и отключить:

              set +H
              

              Ну, либо действительно использовать одинарные кавычки.

              Вот тут хорошее обсуждение по теме.
          0
          Интересная ситуация с именами файлов, которые начинаются с дэфиса.
          А так, спасибо за интересные извращения аля hex-имена, такое в голову не пришло бы…
            0
            Еще один момент есть по поводу служебных символов — это бэкслэши в именах файлов. При просмотре один бэкслэш ( \ ), при удалении его, соответственно, надо экранировать им же, то есть удваивать.
              +17
              В man хорошо описано:
              ОПЦИИ POSIX
              [--] Завершает список опций.

              touch -- -abc
              rm -- -abc
              
                0
                спасибо, добавил в пост
                +2
                Еще в ~/.inputrc можно добавить строчку
                TAB: menu-complete

                И тогда по табу bash будет перебирать варианты, сразу подставляя их в командную строку, как vim.
                  +3
                  Огонь! Спасибо! Из всего что есть — самое универсальное для себя взял вот это:
                  select i in *; do rm -f $i; done
                  А бывают папки в которые попасть можно вот так(до этого делал так: mc, переход в папку, ctrl^o):
                  select i in *; do cd $i; done
                    0
                    В никсах для rm не предусмотрено стандартного или хотя бы распространённого способа отката удаления, вроде «корзины» в Windows?

                    Да, я знаю про никсовую философию, которая даёт пользователю широкие возможности по порче файлов и системы, предполагая, что он «знает, что делает», но ведь все мы люди и склонны ошибаться.
                      +6
                      Так в Windows DEL тоже мимо корзины удаляет. А всякие Nautilus корзинкой пользуются.
                        0
                        О, вроде и там и там можно указать ключик для интерактивного удаления и на каждый файл будет спрашивать что с ним делать.
                          0
                          Shift+Del — мимо корзины.
                          Del — в корзину (если корзина не отключена)
                            +4
                            Я так подозреваю, что vlivyur говорил всё-таки про команду DEL.
                              0
                              Пожалуй, вы правы.
                                +1
                                Да.
                              0
                              Ну так можно использовать UNDELETE =)
                              Это если FAT и постоянно не производится запись на диск.
                              А так команда порой выручала.
                              Шла в составе MS-DOS 5 и выше, если не ошибаюсь.
                              +6
                              Во всех ОС в корзину удаляют только GUI программы, которые работают с юзером. Если с командной строки удалять файл, то в корзину он не попадает, т.к. кто знает, может это скрипт удаляет временные файлы и их создают и удаляют тысячами каждую секунду.
                                +2
                                Корзина есть не что иное, как специальная папка для «удаленных» файлов. И в Windows тоже.
                                Так что можете создать новую, или использовать имеющуюся, и вместо удаления переносить туда файлы.
                                Делов-то.
                                  0
                                  ага, и создать alias на команду rm
                                    +2
                                    Только не будет функции восстановления и из файлов с одинаковыми именами выживет лишь последний.
                                      0
                                      Ну это смотря какой именно алиас навернуть… Там ведь можно всякое сделать. Про trash-cli на питоне, например, ниже уже писали.
                                      +1
                                      Еще лучше создать alias shd
                                       alias shd='rm -rf ~'
                                      (это шутка, как в рекламе, не нужно это пытаться повторить в действительности :) )
                                    0
                                    +1
                                    Как видно, чтобы осуществить правильное перекодирование нужно знать две кодировки: предполагаемую кодировку файла и кодировку нашего терминала.

                                    Я бы был поосторожнее с такой формулировкой. Тут скорее смысл не в том чтобы сделать кодировку файлов такой же как и кодировка терминала (которая могла случайно оказаться таковой в данный момент), а хорошо подумать в какой кодировке должны быть ваши файлы в итоге.
                                      +3
                                      Что-то мне кажется что -f примерах — лишнее. Постановка -f должна быть осознана под ситуацию.
                                        +4
                                        > С помощью одинарных кавычек нельзя удалить файл, в названии которого есть одинарная кавычка, даже заэкранировав ее.

                                        На всякий случай: rm 'actually it'\''s easy'
                                          –5
                                          Вообще, для команды rm у Linux GURU есть чудесное правило. Называется — «правило двух рук».
                                          Перед запуском команды рукм положить под пятую точку. Затем попробовать «поднатужиться».
                                          Если получится как у прапорщика в анекдоте — появится дополнительное время для обдумывания, пока будет приниматься душ и стираться белье… Если нет — смело жать «Enter» — ОНО само придет! :)
                                            0
                                            Угу. А в ~/.my.cnf (при работе с MySQL) дописать:

                                            safe-updates
                                            

                                            Или при запуске клиента передавать опцию --safe-updates, либо --i-am-a-dummy (тот же эффект).

                                            В этом режиме нельзя выполнить запрос DELETE или UPDATE, если в нём не указано условие WHERE. Поэтому, если вы случайно забыли добавить WHERE, то вы просто получите ошибку:

                                            ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
                                            

                                            По умолчанию этот режим, кстати, добавляет ещё пару ограничений (которые, впрочем, можно отключить — но на практике это требуется редко): для select_limit устанавливается значение 1000, а для max_join_size — 1000000.
                                            +6
                                            я невнимательный. комментарий удалён.
                                              0
                                              Если имя файла содержит символ в кодировке utf8, который мы не можем набрать на клавиатуре, то удалить такой файл можно выделением его мышкой, копированием в буфер обмена и последующей вставкой на ввод команды rm.

                                              А если я без иксов сижу, есть способ?
                                                +5
                                                Как вариант
                                                ls > file
                                                Удаляете всё ненужное в виме, дописываете rm. Потом sh ./file Теоретически должно сработать
                                                  0
                                                  Вы в консоли без мыши сидите? Откройте для себя gpm.
                                                    0
                                                    Нет, не сижу. Просто заинтересовало, есть ли такая возможность вообще. Спасибо за наводку. Обязательно открою.
                                                      +2
                                                      gpm для мыши, mplayer через фреймбуфер, графический режим links через тот же фреймбуфер, screen для нарезания экрана на части, активное использование Alt+F[1-6]. И зачем вообще иксы?
                                                      Жаль нвидиовские проприетарные дрова с фреймбуфером не дружат.
                                                        0
                                                        В Gentoo Wiki пишут, что можно поставить uvesafb.
                                                          0
                                                          Спасибо. Но пробовал. Много что уже пробовал.
                                                            0
                                                            Скажите пожалуйста, а есть что-то кроме mplayer'а для просмотра в полный экран через фреймбуфер с сохранением соотношения сторон?
                                                            А то я так месяц просидел с фреймбуфером раз, на иксы ушел только из-за отсутствия нормального сохранения соотношения сторон автоматом, руками надо было параметр выставлять. Или сейчас mplayer так умеет?
                                                              0
                                                              К сожалению у меня сейчас уже не сохранился конфиг, а фреймбуфр работает так себе.

                                                              Не помню удавалось ли мне решить проблему в общем виде одним конфигом, но кажется да. Может при помощи фильтра.

                                                              В худшем случае можно запускать скриптом: через mplayer -ao null -vo null -frames 0 -identify "$@" выцепить оригинальный размер (ID_VIDEO_WIDTH и ID_VIDEO_HEIGHT) и отмасштабировать (разрешение можно взять из /sys/class/graphics/fb0/virtual_size).
                                                                0
                                                                Спасибо. Я как-то так и запускал, но, к сожалению, работало не всегда корректно, через раз. Может быть старое ПО было на тот момент. Одним конфигом добиться вообще не удалось, вычислял скриптом.
                                                                  0
                                                                  На сколько я помню конфигом можно указать одно желаемое измерение, чтобы второе изменилось пропорционально и тогда как повезет. Либо второе влезет, либо не влезет.
                                                            0
                                                            Не правильно выразился. Оно действительно работает, но не родное для монитора соотношение сторон смотрится, мягко говоря, плохо.
                                                      0
                                                      Как быстрый и простой вариант — всякие «плохие» файлы кучей можно удалять через midnight commander, если он есть в системе конечно.
                                                        0
                                                        Это естественно, просто автор поста еще в первом абзаце отказался от любых файловых менеджеров.
                                                      +4
                                                      $ rm -f *
                                                      

                                                      С этим аккуратнее. Представьте, что найдётся файл с названием "-r".
                                                      • НЛО прилетело и опубликовало эту надпись здесь
                                                          0
                                                          Ладно, если только на китайском. Вообще с произвольным набором иероглифов из разных языков без какой-то систематики.
                                                            +2
                                                            Достаточно просто zip распаковать.
                                                            0
                                                            Маски — не панацея! Или, по крайней мере, используйте "./*" (но это не съест файлы, начинающиеся с точки)

                                                            datacompboy@nuuzerpogodible:~$ touch ./-rwer.qqq
                                                            datacompboy@nuuzerpogodible:~$ rm *qqq
                                                            rm: неверный ключ — w
                                                            Попробуйте «rm ./-rwer.qqq», чтобы удалить файл «-rwer.qqq».
                                                            Попробуйте «rm --help» для получения более подробного описания.
                                                            datacompboy@nuuzerpogodible:~$
                                                              0
                                                              Как в статье и указано, для файлов, начинающихся с минуса, нужно использовать --
                                                              rm -- *qqq

                                                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                            Самое читаемое