Вопрос или проблема
Задаваясь вопросом, какая может быть польза от команды 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".
Пример:
Попробуем разобрать на примере, что происходит:
-
Внутренняя команда:
yes yes
– это бесконечный поток вывода строки "yes". Она просто безостановочно печатает "yes\n". -
Внешняя команда:
yes $(yes yes)
– в этом случае командаyes
ожидает аргумент. Аргументом становится вывод внутренней команды. -
Процесс подстановки: Процесс подстановки $(yes yes) должен считывать всю бесконечно растущую строку "yes", чтобы затем передать её в качестве аргумента для внешней команды
yes
. Это приводит к наполнению всей доступной памяти перед тем, как выполнение команды завершится с ошибкой недостатка памяти (Out of Memory).
Применение:
Понимание этой конструкции помогает узнать о поведении системы при неблагоприятном всплеске использования ресурсов. Хотя команда yes
по замыслу полезна для автоматизации пользовательского ввода, например, для автоматического подтверждения запросов, вызов yes $(yes yes)
влечет за собой чрезмерное и быстрое исчерпание ресурсов системы. Этот опыт аналогичен запуску других бесконечных командных процессов, которые могут тормозить или временно нарушать работу системы.
В реальных мировых сценариях знание об этой особенности может быть использовано для тестирования устойчивости системных ограничений, мониторинга поведения систем в условиях исчерпания ресурсов, и улучшении навыков управления ресурсами.
Более того, в ситуации, когда ваш терминал внезапно становится недоступным из-за такого неправильного выполнения команды, решение такой проблемы – важнейшая часть мониторинга и поддержки Unix-подобных систем.
Рекомендации:
В случае необходимости использования yes
с подобной структурой, уделяйте особое внимание:
-
Ограничению ресурса: Используйте такие утилиты как
head
для ограничения количества выводимых строк. Например,yes yes | head -n 100
. -
Обработке ошибок: Убедитесь, что ваши сценарии могут корректно справляться с ситуациями, в которых нехватка ресурсов может оказать воздействие на выполнение команд, включая использование служб мониторинга для заранее выявления таких сценариев.
-
Безопасности исполнения: Всегда тестируйте сложные команды в контролируемой среде, чтобы избежать последствий нарушения производительности операционной системы.
Следование этим рекомендациям обеспечит наибольшую надежность при работе с командами, вызывающими значительную нагрузку на системе.