Насколько безопасно выводить на <dir> одновременно с rm <dir> / *

Иногда мне нужно удалить все содержимое каталога и создать там новые файлы. Могу ли я сделать что-то подобное и ожидать, что все новые файлы останутся нетронутыми:

% rm -rf regression/* & ( sleep 10 ; run_regression ) 

где run_regression временные метки своих выходных файлов, чтобы они имели уникальные имена и run_regression их в regression ?

Я считаю, что оболочка разрешит regression/* в явный список ранее существовавших имен файлов, а затем rm будет удалять файлы в этом явном списке, но не новые файлы, которые run_regression будут создавать одновременно с rm . Поскольку run_regression временные отметки, его файлы не должны встречаться с именами.

Тем не менее, я не совсем уверен, как сказать, когда оболочка закончила перечислять файлы, а rm начинает работать. Является ли выше 10 секунд адекватным? Могу ли я сделать что-то подобное в bash :

 % rm -rf regression/* & ( wait_unil_names_are_resolved ; run_regression ) 

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

5 Solutions collect form web for “Насколько безопасно выводить на <dir> одновременно с rm <dir> / *”

Это небезопасно.

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

 touch regression.delete \ && find regression \! -newer regression.delete -delete & \ && sleep 1 \ && run_regression 

У этого будут проблемы, если у вас есть подкаталоги, вместо этого вы можете написать

 touch regression.delete \ && find regression -mindepth 1 -maxdepth 1 \! -newer regression.delete -exec rm -rf '{}' \; & \ && sleep 1 \ && run_regression 

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

 mkdir regression.new \ && chmod --reference regression regression.new \ && mv regression regression.delete \ && mv regression.new regression \ && rm -rf regression.delete & \ run_regression 

Это должно позволить вам начать run_regression почти мгновенно.

Отвечая на ваше редактирование (и отредактировав себя после исследования в другом ответе), подстановочные символы должны быть расширены до запуска команды rm , но суть проблемы заключается в том, чтобы узнать, выполняется ли расширение после вилки оболочки. Спецификация POSIX асинхронного выполнения явно не указывает так или иначе, насколько я могу видеть, и раздел 2.1, безусловно, подразумевает, что расширение является отдельной операцией и до фактического fork / exec команды, но тестирование (by @adonis, реплицировано я использую bash 4.3.42 (1)) показывает, что bash берет наиболее эффективный способ: если расширение подстановки требует времени, модификации, выполняемые следующей командой, могут влиять на это расширение. Поэтому исходная идея может быть удалена из файлов, которые вы не хотите удалять.

Я посмотрел на источник bash, и execute_cmd.c явно заявляет, что fork выполняется перед расширением слова:

 3922 | /* If we're in a pipeline or run in the background, set DOFORK so we 3923 | make the child early, before word expansion. This keeps assignment 3924 | statements from affecting the parent shell's environment when they 3925 | should not. */ 

Хотя ваша команда, вероятно, работает, вот пример:

 $ ls $ echo * $(sleep 1)&touch file1 [1] 12798 $ file1 [1]+ Done echo * $(sleep 1) 

Обратите внимание, что file1 не был введен, это был результат команды echo.

Редактировать:

Другой тестовый прогон:

 $ ls $ touch file1 $ for i in {1..5000}; do rm * & touch file$i; wait;done|grep file rm: cannot remove '*': No such file or directory ***previous line repeated 14 times*** 

rm -rf regression/* работает параллельно с ( sleep 10 ; run_regression ) . Это означает, что у вас нет гарантии относительно порядка вещей. rm -rf regression/* сначала собирает список файлов в каталоге regression , а затем вызывает rm для их удаления. Это не происходит по волшебству, это оболочка, выполняющая работу как часть оценки команды rm -rf regression/* , и это происходит после вилки, вызванной оператором & . Если шаг сбора занимает менее 10 секунд, файлы, созданные run_regression , безопасны. Если для шага сбора потребуется более 10 секунд, чтобы достигнуть файла, созданного run_regression , этот файл будет удален.

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

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

Если вы действительно хотите сохранить каталог и удалить файлы в нем, сначала создайте коллекцию имен файлов.

 files_to_delete=(regression/*) rm -rf "${files_to_delete[@]}" & run_regression 

(Предполагается, что файлы run_regression создают только файлы, которые не существуют, если они перезаписывают существующие файлы, то эти файлы будут удалены.

Вам, вероятно, не нужна вся эта сложность: просто запустите

 rm -rf regression/* run_regression 

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

Если производительность операции удаления очень плохая (что, опять же, было бы необычно), создайте новый каталог.

 mv regression regression.old mkdir regression rm -rf regression.old & run_regression 
 mv regression regression.old rm -rf regression.old & mkdir regression run_regression 

Переименуйте старый каталог регрессии, удалите его в фоновом режиме, создайте новый каталог регрессии, а затем запустите свою программу.

если run_regression создает сам каталог, если он не существует, то третий шаг не требуется.

Более безопасная версия, в случае, если regression.old уже существует, было бы использовать mktemp для создания и использования временного каталога в текущем каталоге:

 td=$(mktemp -d -p .) mv regression "$td/" rm -rf "$td" & unset td mkdir regression run_regression 

Это безопасно, если вы используете новые имена файлов. Оболочка знает о именах файлов, а не об их inode и т. Д., И делает флешинг (расширение подстановочных знаков) перед запуском команды. Согласно POSIX :

2.6.6 Расширение пути

После разделения поля, если set -f не действует, каждое поле в полученной командной строке должно быть расширено с использованием алгоритма, описанного в Обозначении соответствия шаблонов , который определяется правилами в шаблонах, используемых для расширения имен файлов .

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

2.9.1 Простые команды

  1. Слова, которые не являются переменными назначениями или перенаправлениями, должны быть расширены. Если после их расширения остаются какие-либо поля, первое поле считается именем команды, а остальные поля являются аргументами для команды.

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

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

  • Какова идея, по которой rm не удаляет файл без записи по умолчанию?
  • Не удается удалить каталог, операция не поддерживается в NTFS
  • Почему rm медленно?
  • Непоследовательность в поведении «rm» при подключенном томе?
  • «Rm -rf $ dir» когда-либо возвращается false?
  • Удалить файл, но только если это символическая ссылка
  • Как удалить каталог и все его содержимое?
  • ограничение прав учетной записи пользователя и приложений на безопасность, защита содержимого домашней директории от несчастных случаев
  • Как удалить файл с именем «>»?
  • Поведение rm - как предотвратить удаление содержимого установленных точек
  • удалить каталог со специальным символом в имени файла
  • Interesting Posts

    Работа с вспомогательными подкомандами последних инструментов CLI

    Защита паролем файла LibreOffice или OpenOffice ODT от Bash

    Замена скрипта оболочки во время его запуска

    Что делает xargs, если он используется без каких-либо параметров?

    Можно ли использовать «.» Для запуска файлов вместо источника в .bashrc в Ubuntu и OS X?

    передача паролей в скрипт

    Desktop Environment, которая масштабирует графический интерфейс в соответствии с DPI и размером монитора

    Как запускать команды терминала и выполнять команды на Linux (Mint 17.2, KDE, плазма)?

    Не заблокирован экран блокировки CentOS

    Как изменить индекс поиска в Ubuntu 11.04?

    Конвенция для основной структуры развертывания приложений на Unix-подобном сервере приложений

    Можно ли отключить возможность установки из репозиториев yum, которые могут включать зависимости?

    Система продолжает запрашивать у меня пароль root вместо моего пароля!

    Сообщение о неполадке Arch от локали

    Как запустить ADB в initramfs?

    Linux и Unix - лучшая ОС в мире.