Запретить вводу пользователем случайного пробела между rm и подстановочным знаком

29

Намерение:

rm -rf string*

Проблема:

rm -rf string *

Первый случай - законное и распространенное использование rm, во втором случае небольшая опечатка может вызвать много проблем. Есть ли простой способ разумной защиты от случайного трейлинга или лидирующего символа подстановки?

bobdole
источник
8
С недавней и хорошо настроенной оболочкой ( zshили bash) я бы предпочел нажать клавишу табуляции (чтобы вызвать автозаполнение), прежде чем нажимать клавишу возврата
Василий Старынкевич
2
touch -- -iсоздаст файл, -iкоторый будет передан в rmкачестве параметра -iпри включении подстановочного знака в ваши аргументы.
Восстановить Монику - М. Шредер
@ MartinSchröder: Если вы оказались в каталоге, где существует файл.
Приостановлено до дальнейшего уведомления.
@ MartinSchröder Это будет работать только если вы печатаете rm *. Если вы напечатаете rm name *, он расширится до rm name -i other names. -iне будет обрабатываться как опция, потому что это не перед именами файлов.
Бармар
1
Как правило, пользователь делает это только один раз.
tedder42

Ответы:

37

DEBUGЛовушка может быть написана для отмены команды , которые выглядят подозрительно. Следующее или похожий на него код можно добавить к вашему ~/.bashrc:

shopt -s extdebug
checkcommand() {
  if [[ $BASH_COMMAND = 'rm -r'*' *' ]]; then
    echo "Suppressing rm -r command ending in a wildcard" >&2
    return 1
  fi
  # check for other commands here, if you like
  return 0
}
trap checkcommand DEBUG

Отрегулируйте логику по вкусу.

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

Чарльз Даффи
источник
47

Там нет никакого способа, чтобы полностью пуленепробиваемые системы. И добавив "Вы уверены?" подсказки к вещам и контрпродуктивны и приводят к «Конечно, я уверен». коленные реакции.

Уловка, которую я взял из книги прошлых лет, состоит в том, чтобы сначала сделать ls -R blah*то, что делать, rm -fr blah* если и только если список, который появился, достиг того, что я хотел ударить.

lsСначала достаточно просто выполнить команду, затем удалить ls -Rи заменить на rm -fr.

Последний вопрос: «Если информация была полезна для вас, где ваша резервная копия?»

killermist
источник
4
Вместо стрелки вверх вы можете использовать ^ls -R^rm -rf^и, возможно, установить в качестве псевдонима
exussum
FWIW, это то ls -R, что я в основном делаю все время, но это настолько инстинктивно, что в этот момент мое сознание ускользнуло, когда я сформировал ответ. Так что +1 за это.
JakeGould
Это также имеет то преимущество, что это не принесет вреда, если вы нажмете клавишу ввода, или ударьте мышью и вставите что-нибудь с символами новой строки. Я иногда ввожу вещи в менее эффективном порядке просто для большей безопасности, например cat > .log, затем возвращаюсь и вставляю или дергаю имя файла перед .log. Так что ни в коем случае я не имею > valuablefileна cmdline.
Питер Кордес
Я использую rm с псевдонимом для rm -i, поэтому я часто просто сочиняю свою команду rm, а затем помещаю a \ в начале строки. ( \rmизбегает расширения псевдонимов для rm, так как часть слова была заключена в кавычки). Если мне нужно были -rили -f, да , я иногда начинаю с lsвместо rmили просто уйти от в -rfчасти. (Отредактируйте, как вы получаете форматирование кода с обратной косой чертой? bquote bslash bslash bquote не удается.
Питер Кордес
8

Можете ли вы научить себя использовать, скажем, rmrfвместо rm -rf?

Если это так, эта функция bash предоставит вам шанс увидеть, что на самом деле произойдет, прежде чем подтвердить команду:

rmrf() { echo rm -rf "$@"; read -p "Proceed (y/N)? "; [ "${REPLY,,}" = y ] && rm -rf "$@"; }

Чтобы сделать эту функцию постоянной, добавьте эту строку в ~/.bashrcфайл на каждом используемом компьютере.

Сравнение с общим rmпсевдонимом

Обычно называют псевдоним:

alias rm='rm -i'

Это имеет два ограничения:

  1. Если вы зависите от этого псевдонима, то вы будете шокированы, когда находитесь на машине или в среде, где ее нет. Напротив, попытка запустить rmrfна машине без этой функции вернет безвредность command not found.

  2. Этот псевдоним не поможет в вашем случае, потому что -fпараметр, который вы указали в командной строке, переопределяет -iпараметр в псевдониме.

John1024
источник
4
Неплохая идея. Но это зависит от того, установлена ​​ли эта функция и доступна ли она на любых системах, которые использует этот пользователь. Допустим, они входят на удаленный сервер для какой-то работы и запускают неправильную rm -rfкоманду, что происходит? Создание подобных псевдо-функций в конечном итоге просто усложняет простое решение: просто будьте осторожнее и понимайте, что такое разрешения.
JakeGould
4
@JakeGould И не используйте rm -f, если вам действительно не нужно .
CVn
1
Зачем беспокоиться rmrf, в отличие от простого создания функции оболочки, rmкоторая проверяет аргументы -rили -rf, и в этом случае применяет специальную логику, в противном случае напрямую вызывая command rm "$@"для вызова реальной rmкоманды?
Чарльз Даффи
3
Вы используете другое имя, поэтому вы не стреляете себе в ногу, когда нет переопределения. И я согласен с @ MichaelKjörling, вам не нужно, -fесли у вас его нет -i. Отключение -fдает вам дополнительное предупреждение, например, перед удалением файла только для чтения.
Питер Кордес
6

Если я нахожусь в ситуации , когда удаление бракованных файлов является действительно большим делом, одна из вещей , которые я сделал , это сделать мусорную корзину папки, как mkdir trashcanи тогда у меня есть сценарий , rmTrashcanкоторый имеет rm -rf trashcan/*или rm -rf *или подобные, написанную очень тщательно и проверил несколько раз.

Таким образом, если я сделаю ошибку, ошибка будет в mvкоманде, а не в rmкоманде. Как только я сделаю lsи уверен в том, что именно я удаляю, он rmTrashcanдействительно выполняет грязную работу безопасно.

Это также было чрезвычайно удобно для ситуации, когда мне приходилось удалять резервные копии. Я мог mvцелый месяц создавать резервные копии в мусорной корзине, mvнемногие я хотел сохранить (1-е число, 15-е число) обратно в резервные копии, а затем rmTranshcanостальные. Выполнение подобной команды сложно выполнить rmсамостоятельно, и выполнение этого таким образом позволило мне lsбыть уверенным в том, какие файлы я оставляю (вместо того, чтобы просто перечислять файлы, которые я намереваюсь удалить).

Корт Аммон - Восстановить Монику
источник
4

Вместо того, чтобы возиться с двумя командами ( lsи rm), я думаю, что проще и проще использовать find:

find . -maxdepth 1 -name "string*" -delete

Если вы случайно наберете текст, "string *"он удалит файлы с именами string charsи string letters(что в любом случае вам и нужно), но он не будет захватывать каждый файл, как *в оболочке.

Кроме того, вы можете пропустить, -deleteчтобы увидеть, какие файлы он собирается удалить, затем нажать стрелку вверх и набрать -deleteтекст легче, чем набирать текст ^ls -R^rm -rfили другие глупости.

няня
источник
A findвыполнит вложенный поиск файлов, которые совпадают, а не только с явными параметрами, объявленными в командной строке. Я думаю, что это не соответствует цели. Хотя я могу ошибаться.
убийца
3

Есть ли простой способ разумной защиты от случайного трейлинга или лидирующего символа подстановки?

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

Это означает, что это все проблема пользовательского интерфейса, даже если он находится на уровне текстовой / командной строки. Сколько сетей безопасности вы ожидаете, чтобы защитить вас от того, что вы не должны делать? Это как ножницы: если вы как-то небрежны, поскользнулись и порезали руку, намереваясь порезать ткань или бумагу, кто виноват? Или даже светофоры и стоп-сигналы: на самом деле ничто не мешает водителю включить свет или игнорировать дорожные знаки, кроме острой осведомленности о том, что может случиться, если они действительно будут вести себя так рискованно.

Тем не менее, лучшее, реалистичное решение заключается в системных правах доступа пользователей и групп. Это лучшая / единственная реальная сеть безопасности для защиты пользователя от себя.

Если вы работаете в системе, где вы единственный, кто имеет к ней доступ, у вас может возникнуть соблазн всего chmod 777, но это не тот способ, которым настроена рациональная система. Вместо этого права доступа должны быть такими же, как 755для всех каталогов и 644для всех неисполняемых файлов. Исполняемые файлы должны быть 755как минимум, но, возможно, даже 744если вы хотите, чтобы другие читали, но не запускали файлы.

JakeGould
источник
2

Попробуйте составить исходную rmкоманду без -fфлага, но -iвместо этого с таким, rmкоторый предложит вам для каждого файла, который он намерен удалить. Для небольших рекурсивных удалений вы можете удерживать yклавишу, если вы уверены, что команда была введена правильно. Для больших удалений вы можете прервать операцию и использовать историю командной строки, чтобы аккуратно изменить на -ia -f.

Невин Уильямс
источник
На самом деле вам нужно нажать на y[RETURN]каждый файл, с GNU rm вы ничего не сможете удержать. Редактирование -i- это путь, когда вы правильно набрали команду. Тогда вы получите приглашение только для файла, доступного только для чтения, и, возможно, других вещей.
Питер Кордес
1
Просто используйте его, rm -Iчтобы он запрашивал только один раз и только для потенциально опасных удалений (т.
Ник Маттео
1
На менее конструктивных форумах мой ответ был бы примерно таким: «Если вы печатаете / корректируете так плохо, вам не нужно использовать« rm -rf »с подстановочными знаками». Я не знал о переключателе ... Должно быть, его вставили <20 лет назад; «о последний раз, когда я сделал« человек рм ». :)
Невин Уильямс
2

У rm есть -iи -Iфлаги для подтверждения перед каждым удалением. В прошлом некоторые дистрибутивы включали их по умолчанию. Это ужасная идея. Дайте пользователю слишком много диалогов подтверждения для обычных операций, и они начнут их обычное подтверждение. Это просто сдвигает требование «быть осторожным» (всегда красным флажком) в новый и более раздражающий диалог. "Да. Да. Да. Да! ДА! Черт возьми, тупой компьютер, просто удалите файлы ДА-ДЕС-ДЕС-ДЕС - ХЛОПОТ Я НЕ ЗНАЮ! Это проблема диалога «Да, но я имел в виду нет». Этот ответ дает наглядное объяснение того, почему диалоги подтверждения приходят не вовремя.

Тип ошибки, которую вы описываете, - это промах , «выполнение действия, которое не было тем, что было задумано». Пользователь обычно сразу распознает ошибку и точно знает, как ее исправить. К сожалению, Unix не дает пользователю возможности, rm немедленно удаляет файл. Любая другая операционная система решает эту проблему, позволяя удалять, по крайней мере, на некоторое время, с помощью корзины.

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

Вопрос в псевдониме rm или нет в псевдониме rm. Плюсы для алиасинга рм ...

  1. Вы не можете забыть об использовании альтернативы rm.

Минусы для псевдонимов ...

  1. Вы можете полагаться на это в системах, в которых этого нет.
  2. Может вызвать проблемы, когда диск почти заполнен.
  3. Нужна инфраструктура для периодической очистки мусора.
  4. Должны быть уверены, что не мешают ожидаемому поведению rm в программах.
  5. Может не полностью подражать рм.

Если вы будете следовать первому аргументу слишком далеко, вы будете использовать vi (не vim, vi), csh (не tcsh, csh) и другие устаревшие утилиты, потому что они доступны повсеместно. Тем не менее, существует опасность перенастройки вашей среды. Я предпочитаю брать с собой свои коммунальные услуги и делать это как можно проще. YMMV.

Два и три являются техническими проблемами. Они могут быть решены с помощью умного жнеца, который проверяет размер мусора и периодически убирает вещи, как в случае с жнецом . Это может быть задание cron или более умная версия, в которой можно использовать различные инфраструктуры событий файловой системы, доступные во многих дистрибутивах Linux для настольных компьютеров. Это не просто, а еще сложнее сделать эффективно. Лучше найти существующую систему, чем пытаться создать собственную.

С четвертым можно справиться, сделав ваш новый rm псевдонимом оболочки alias rm='trash', тогда это не повлияет на программы.

Пятая проблема, которую я оставляю читателю для решения. У rm не так много переключателей.

Schwern
источник
У меня есть псевдоним rm -i, но я часто использую его, \rmчтобы получить беспристрастное поведение. Я печатаю rm -iкаждый раз, когда планирую сказать «нет» одному из аргументов. Иногда я запускаю команду с lsпомощью команды, а затем вставляю \ rm только после завершения. Так что я никак не могу случайно нажать «вернуться» rm -rf /вместо/.../file
Питер Кордес
rm -Iили rm --interactive=onceэто намного, гораздо менее раздражает, чем rm -i, и все еще ловит что-то опасное (оно только выдает запрос, когда существует более 3 файлов, или если это рекурсивно, и только ОДИН РАЗ вместо ФАЙЛА ДЛЯ КАЖДОГО ФАЙЛА.)
Ник Маттео
@ Кундор Да, и это не меняет уравнения. Вероятно, это повышает вероятность того, что пользователь проигнорирует это. У пользователя есть цель: удалить материал. В подсказке говорится: «Вы уверены, что хотите удалить материал, который вы только что сказали мне удалить?» Пользователь по-прежнему зациклен на цели удаления материала, не проверяя, что должно быть удалено, поэтому он говорит «да», не задумываясь. -iможет дать пользователю время для изменения целей. Этот ответ на связанный вопрос выкладывается.
Шверн
@Schwern: но никто не может прожить rm -iболее 30 секунд, не выключив его. Принимая во внимание, что rm -Iтолько подсказывает, когда есть вероятность, что вы облажались; приглашение появляется только для больших удалений. Когда вы пытались удалить несколько вещей и выдается приглашение, вы ошеломлены и понимаете, что случайно набрали «foo *».
Ник Маттео
@Kundor Удаление более трех файлов и рекурсивное удаление (подтверждение отключено привычным -rfмною обнаруженным мною) - плохие прокси для обнаружения вероятного сбоя. Желание удалить подкаталог вряд ли облажается. Сообщение не помогает, потому что оно только подтверждает, что пользователь сказал делать, не добавляя полезную информацию в тот момент, когда пользователь не хочет проверять. msgstr "rm: удалить 1 аргумент рекурсивно?" "Да, удалите каталог, я только что сказал вам сделать это! ... подождите, какой каталог это был? CRAP !!!"
Шверн
2

Я учу всех о !$= последнем аргументе в последнем трюке команды:

% ls job[XYZ].*
jobX.out1
jobX.out2
[rest of the matches]

% rm !$

Это позволяет проверить расширение подстановочного знака, а затем использовать точно такой же шаблон глобуса без возможности вставки пробела перед *.

Также я предлагаю, чтобы люди никогда не вырезали и не вставляли шаблон с подстановочными знаками в потенциально разрушительную командную строку. Потому что в моих руках это было проблемой :)

Техник в моей лаборатории только что сделал эту ошибку на прошлой неделе (3 месяца работы) - и да, у нас была резервная копия (1 день позади).

Кель
источник
0

Кажется, все говорят: «Будь осторожнее», «Не делай подсказок с псевдонимом / подтверждением, потому что ты привык не обращать на это должного внимания».

Круто и все. Я имею в виду, я не думаю, что вы должны сделать псевдоним для rm(ни rmrf, поскольку вы могли бы легко облажаться и набрать настоящую команду).

Но почему вы не можете создать псевдоним / скрипт и, скажем, вызвать его и указать removeтолько один аргумент (например, $ 1)? Подстановочный знак должен быть $ 2 из-за непреднамеренного пробела (amiright?), И, таким образом, ваш скрипт / оболочка / псевдоним не будет передан второму. Да, вы можете делать только один набор удалений (с подстановочным знаком), но это цена, которую вы заплатите.

Если бы я писал что-то приятное, я мог бы попросить сообщить мне количество файлов и каталогов, которые он планирует удалить, и общий размер удаляемых материалов, а затем попросить подтверждения, но это может помешать вашему потоку. Может быть, сделать эту опцию флага remove? (-я). Вы также можете сделать проверку $ 1, чтобы увидеть, является ли это просто одним подстановочным знаком, и запросить подтверждение, и указать, в каком каталоге вы на самом деле находитесь.


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

user3082
источник
6
Ваш псевдоним "удалить" никогда не удалит более одного файла за раз. Вы не можете использовать подстановочный знак, потому что оболочка раскрывает его до того, как команда его увидит.
hymie
Так сделайте eval на этом, и затем включите это в сценарий?
user3082
Так ты хочешь печатать remove \*? Если ваш сценарий позволяет оболочке глобально расширять свой ввод, я не вижу, чтобы это сильно помогало.
Питер Кордес
0

В -rfконце очень простой трюк : rm whatever* -rf
это значительно снижает частоту появления ошибок, потому что вы набираете больше символов после *, и у вас больше времени, чтобы увидеть опечатки.
Это не все решает. Просто простой ежедневный трюк.

Грегори МУССАТ
источник