Что делает yes $(yes yes)?

Вопрос или проблема

Задаваясь вопросом, какая может быть польза от команды yes, я наткнулся на этот комментарий и попытался выполнить

yes $(yes yes)

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

Что здесь происходит?

Для этого уже достаточно выполнить

 echo $(yes yes)

Конструкция $(...) выполняет внутреннюю команду до ее завершения и захватывает весь ее вывод. – Поскольку yes работает долго и генерирует много вывода, оболочка в конечном итоге исчерпает память и зависнет.

Чтобы увидеть сообщение об ошибке, которая закрывает вашу оболочку, нужно запустить под-оболочку.

$ sh
$ kill -9 $$
Killed
$

$ sh
$ yes $(yes yes)
sh: xrealloc: cannot allocate 18446744071562067968 bytes
$

Ответ или решение

Теория:

Команда yes является утилитой в UNIX и Unix-подобных системах, которая беспрерывно выводит аргумент на стандартный вывод, по умолчанию заменяя его на "y", если аргументы отсутствуют. Например, вызов yes yes приведет к постоянному выводу слова "yes" в поток.

Когда выполняется команда yes $(yes yes), происходит двойное использование yes. Комментарий из вопроса на сайте Unix Stack Exchange дает ключ к пониманию природы этой команды. Синтаксис подстановки $() в Bash запускает команду внутри скобок и заменяет ее месте выполнения на весь вывод, который возвратила команда. Поэтому, когда внутренняя yes yes запускается, она начинает бесконечно выводить слово "yes".

Пример:

Попробуем разобрать на примере, что происходит:

  1. Внутренняя команда: yes yes – это бесконечный поток вывода строки "yes". Она просто безостановочно печатает "yes\n".

  2. Внешняя команда: yes $(yes yes) – в этом случае команда yes ожидает аргумент. Аргументом становится вывод внутренней команды.

  3. Процесс подстановки: Процесс подстановки $(yes yes) должен считывать всю бесконечно растущую строку "yes", чтобы затем передать её в качестве аргумента для внешней команды yes. Это приводит к наполнению всей доступной памяти перед тем, как выполнение команды завершится с ошибкой недостатка памяти (Out of Memory).

Применение:

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

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

Более того, в ситуации, когда ваш терминал внезапно становится недоступным из-за такого неправильного выполнения команды, решение такой проблемы – важнейшая часть мониторинга и поддержки Unix-подобных систем.

Рекомендации:

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

  1. Ограничению ресурса: Используйте такие утилиты как head для ограничения количества выводимых строк. Например, yes yes | head -n 100.

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

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

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

Оцените материал
Добавить комментарий

Капча загружается...