Rm. * Удаляет ли родительский каталог?

53

Выражение .*расширяется с помощью bash для включения текущего и родительского каталогов:

$ ls -la
total 2600
drwxrwxrwx   2 terdon terdon 2162688 Sep 10 16:22 .
drwxr-xr-x 142 terdon terdon  491520 Sep 10 15:34 ..
-rw-r--r--   1 terdon terdon       0 Sep 10 16:22 foo
$ echo .*
. ..

Если я запускаю rm -rf .*на своем Debian с помощью GNU bash version 4.2.36(1)-releaseи rmиз rm (GNU coreutils) 8.13, я получаю это сообщение:

$ rm -rf .*
rm: cannot remove directory: `.'
rm: cannot remove directory: `..'

Это вещь GNU или это POSIX? Существуют ли системы * nix, где приведенная выше команда будет молча удалять .и ..?

Кроме того, это функция безопасности оболочки или самой rmкоманды?

Тердон
источник
4
Я знаю , что этот вопрос в контексте rm, но я подумал , что это стоит отметить , что вы можете иметь неожиданные результаты с chmod, chownи т.д. при совмещении .*.
Аарон Копли

Ответы:

59

Версия последней (по состоянию на 2017 г.) в спецификации POSIX для rmутилиты здесь (и предыдущий там ) и запрещает удаление .и ...

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

Как отмечает @jlliagre, часть о /дополнении в SUSv4.

Самая старая общедоступная спецификация Unix, которую я смог найти ( XPF4 CAE rev2 (1994)), уже указала это .и ..не может быть удалена, хотя комментарии в журнале изменений GNU fileutils предполагают, что это уже имело место в более старых спецификациях POSIX.

Обратите внимание, что это относится и к, dir/..и ../к тому же, но некоторые реализации (включая UNIX-сертифицированные, такие как Solaris 11 и macOS) все еще не защищают от rm -rf ../или rm -rf .*/).

история

Ранние объединения

-rОпция rmбыла добавлена в Unix V3 (1973) , хотя это было только удаление содержимого каталогов, вам все равно нужно использовать rmdirдля удаления каталогов.

Это изменилось в Unix V7 (1979, выпуск, который также представил оболочку Bourne и из которой происходит большинство Unices). rm -rтеперь также удаляются каталоги и не будут удалять ..дерево каталогов. На странице руководства государства:

Запрещается удалять файл ..только для того, чтобы избежать антисоциальных последствий непреднамеренного совершения чего-либо подобного rm -r .*.

(хотя можно утверждать, что rm -r .*это антисоциально, поскольку удаляет все, потому что .включено).

Он все же согласился удалить, .хотя он не отменял связь .ни с ..записями, ни с. Итак, rm -r .был эффективный способ очистить текущий каталог.

Также обратите внимание, что гарантия была только для буквального ..аргумента, а не для dir/..или ./... Таким образом, rm -rf ./.*все равно все рекурсивно удаляется из родительского каталога.

Интересно видеть, что это было уже для обхода ошибки / ошибочной характеристики, которую глобусы могли включать .и ..в их расширение. Это было исправлено в оболочке Forsyth (основа для оригинальной оболочки Minix и pdksh) в конце 80-х zsh(1990) и fish(2005), но не в других оболочках и, в частности, не в shязыке POSIX, который требует расширения .*для включения .и, ..если они возвращаются readdir()( bashрешает проблему частично только в shopt -s dotglobтех случаях, когда глобусы (кроме .xxxтех) не включают .или .., и, с помощью ksh, вы можете исправить это, выполнив FIGNORE='@(.|..)').

Когда .было добавлено точное запрещение, это не всегда понятно и зависит от каждого Unix. Несколько выводов ниже.

BSDs

Запрещая из .добавляли то между 2.9BSD (1983) и 2.10BSD (1987) , а также между 4.2BSD (1983) и 4.3BSD (1986) (см это изменение датируемые 1985 в unix-истории-репо ).

$ wget -qO- http://www.tuhs.org/Archive/PDP-11/Distributions/ucb/2.9BSD/root.tar.gz |
    zgrep -ao 'rm: canno[[:print:]]*'
rm: cannot remove `..'
$ wget -qO- http://www.tuhs.org/Archive/PDP-11/Distributions/ucb/2.10bsd.tar.gz |
    zgrep -ao 'rm: canno[[:print:]]*'
rm: cannot remove `.' or `..'
rm: cannot remove `.' or `..'\n");

Для dir/.и dir/..см это изменение в 1988 году (BSD 4.3 Net / 1).

На данный момент rmFreeBSD (и его производные, такие как macOS) по-прежнему очищают текущий или родительский каталог rm -rf ./или rm -rf ../хотя бы (имеет значение для rm -rf .*/).

Система V

У меня не так много информации, так как ни исходный, ни двоичный файлы не доступны для производных AT & T Unix после V7. В своем электронном руководстве, HPUX ( на основе System III) до сих пор упоминает , что он только запрещает , ..а эффективно это запрещает и что является свидетельством того, что , вероятно , по крайней мере , SysIII не запрещает удаление .( редактирование : Теперь , глядя на в SysIII rmисходном коде , это практически не изменился со времен Unix V7).

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

Solaris по- rmпрежнему очищает текущий или родительский каталог после rm -rf ./или rm -rf ../.

GNU

Рано изменений для FileUtils GNU имеет всю историческую информацию.

Хотя первоначально ни удаление, .ни ..были запрещены, ..сначала было запрещено, а затем оба (включая dir/.), все в период с 1990 по 1991 год.

Другие

Как мы видели zsh, расширение .*(или любой глобус) никогда не включает .или ..(даже в shрежиме эмуляции). Поэтому rmвстроенный (который вы получаете, если вы zmodload zsh/files) не относится .или ..специально. Таким образом, с этим zshвстроенным, вы можете rm -rf .или rm -rf ..очистить .или .., но rm -rf .*не удалит .или ...

В busybox rmзапрет на удаление .и ..был добавлен в 0.52 (2001)

Стефан Шазелас
источник
Странно, но это указывает на то, что rm -rf . /(обратите внимание на пробел) следует вывести два предупреждения (для .и /) и завершиться, но у нас, похоже, возникает вопрос, как восстанавливаться после этого каждые пару месяцев.
Кевин
6
@Kevin Не все системы совместимы с POSIX, а ограничение корневого каталога было добавлено только явно в последней версии POSIX.
июля
@jlliagre я вижу. GNU, как правило, пытается реализовать POSIX (+ расширения, конечно), и я думаю, что они захотят вставить это, но если это будет довольно новым, это объяснит.
Кевин
2
@Stephane: вы правы, но я бы еще добавил большое «Да, это может произойти! Но ...» в начале вашего ответа, так что люди, несомненно, знают, что действительно, на некоторых (старых или просто не -POSIX-совместимые) системы, они могут удалять родительские каталоги. Я стараюсь всегда указывать на такую ​​возможность (то есть я стараюсь оставаться в безопасности, даже если это иногда затрудняет чтение / запоминание ответа) ^^
Оливье Дюлак
1
@ MartinSchröder, на BSD он был добавлен где-то между 2.8BSD и 2.10BSD (раньше было запрещено «...», как в UnixV7) и ​​между 3BSD и 4.3RENO. На системах SysV это менее понятно. Руководство HPUX, например, утверждает, что оно запрещает только "..", но фактически запрещает оба "." и "..", это только руководство, которое не обновлено.
Стефан Шазелас