Вопрос или проблема
У меня есть следующий простой скрипт bash (называется test.sh
), который показывает использование диска в корневом каталоге. Для списка всех директорий требуется sudo
(и меня не запрашивают пароль sudo
).
#!/bin/bash
sudo du -h --max-depth=1 / 2> /dev/null
Каталог находится в моем пути, и затем я запускаю скрипт так (чтобы получить вывод в текстовый файл):
$ ./test.sh >> ./test.txt
Теперь, если я приостановлю задачу с помощью Ctrl+Z, я получаю следующее:
^Z
[1]+ Stopped ./test.sh >> ./test.txt
Если затем я возобновляю выполнение в фоне с помощью bg
, я все равно получаю:
$ bg
[1]+ ./test.sh >> ./test.txt &
[1]+ Stopped ./test.sh >> ./test.txt
$ jobs
[1]+ Stopped ./test.sh >> ./test.txt
(Дополнительные попытки с bg
могут привести к тому, что скрипт действительно возобновит выполнение в фоне после 2-3 попыток, но это кажется случайным…)
Однако, если я возобновляю выполнение с fg
, тогда скрипт выполняется на переднем плане:
$ fg
./test.sh >> ./test.txt
И результат записывается в test.txt
:
3.8M /root
4.0K /authentic-theme
4.0K /srv
72K /tmp
3.2G /snap
4.0K /media
8.4M /etc
0 /proc
0 /sys
4.0K /cdrom
16K /opt
16K /lost+found
24K /dev
4.3M /run
263G /mnt
14M /home
19G /var
245M /boot
3.8G /usr
297G /
Если я изменяю скрипт так, чтобы не использовать sudo
(и вместо этого запускаю скрипт с sudo
), то я могу возобновить выполнение в фоне нормально с bg
, и скрипт выполняется:
$ sudo ./test.sh >> ./test.txt
^Z
[1]+ Stopped sudo ./test.sh >> ./test.txt
$ bg
[1]+ sudo ./test.sh >> ./test.txt &
$ jobs
[1]+ Running sudo ./test.sh >> ./test.txt &
То же самое происходит, если я запускаю всю команду с sudo
, но не как скрипт:
$ sudo du -h --max-depth=1 / 2> /dev/null >> ./test.txt
^Z
[1]+ Stopped sudo du -h --max-depth=1 / 2> /dev/null >> ./test.txt
$ bg
[1]+ sudo du -h --max-depth=1 / 2> /dev/null >> ./test.txt &
$ jobs
[1]+ Running sudo du -h --max-depth=1 / 2> /dev/null >> ./test.txt &
Может ли кто-нибудь объяснить, что здесь происходит? Почему вы можете возобновить команду, использующую sudo
, а также скрипт в фоне, но когда скрипт содержит точно такую же команду с sudo
, то возобновление выполнения в фоне с bg
, по-видимому, не работает корректно?
Я использую Ubuntu 22.04.1 с версией Bash по умолчанию 5.1.16.
Редактирование #1: Я могу сообщить, что у меня настроен alias sudo='sudo '
, чтобы команды с sudo
могли использовать другие алиасы. Однако я тестировал и с этим алиасом, и без него, и в любом случае получал ту же нерегулярную реакцию bg
на возобновление.
Редактирование #2: jobs -l
дает следующую нормальную информацию:
jobs -l
[1]+ 1074808 Stopped ./test.sh >> ./test.txt
Редактирование #3: Обычно я работаю в tmux
, но я также тестировал без tmux
, и проблема все еще сохраняется.
Редактирование #4: Помимо моего сервера SuperMicro, у меня также есть Raspberry Pi и виртуальная машина Ubuntu для тестирования на моем ноутбуке (Aorus X5). Вот где становится действительно странно:
- На моей виртуальной машине Ubuntu (на VMWare под Windows 10) этой проблемы не происходит вообще. Все корректно возобновляется в фоне с
bg
с первого раза во всех случаях. - На моем Raspberry Pi проблема тоже присутствует – обычно требуется 2-3 попытки с
bg
, чтобы она корректно возобновила выполнение.
Я начинаю думать, что мне нужно тестировать с учетом программного обеспечения, которое работает как на моем основном сервере, так и на моем Raspberry Pi, но не на моей виртуальной машине.
Редактирование #5: Установка stty -tostop
перед запуском скрипта, к сожалению, не особо помогает. В большинстве случаев все еще требуется 2-3 попытки, чтобы корректно возобновить выполнение. Несколько раз это удавалось с первой попытки, но я думаю, что это скорее случайность, чем что-то другое.
Редактирование #6: Вот службы, запущенные на моем Raspberry Pi:
$ systemctl --type=service --state=running
UNIT LOAD ACTIVE SUB DESCRIPTION
atd.service loaded active running Планировщик отложенного выполнения
containerd.service loaded active running контейнерная среда выполнения containerd
cron.service loaded active running Демон регулярной обработки фоновых программ
dbus.service loaded active running Системная шина сообщений D-Bus
docker.service loaded active running Контейнерная среда выполнения Docker
[email protected] loaded active running Сеанс на tty1
irqbalance.service loaded active running демон irqbalance
ModemManager.service loaded active running Менеджер модемов
networkd-dispatcher.service loaded active running Демон диспетчера для systemd-networkd
packagekit.service loaded active running Демон PackageKit
polkit.service loaded active running Менеджер полномочий
prometheus-node-exporter.service loaded active running Экспортер Prometheus для метрик машины
rsyslog.service loaded active running Служба системного логирования
[email protected] loaded active running Последовательный сеанс на ttyS0
smartmontools.service loaded active running Демон самомониторинга и отчетов (SMART)
snapd.service loaded active running Демон Snap
ssh.service loaded active running Сервер защищенных оболочек OpenBSD
systemd-journald.service loaded active running Журнальная служба
systemd-logind.service loaded active running Управление пользовательским входом
systemd-networkd.service loaded active running Конфигурация сети
systemd-timesyncd.service loaded active running Синхронизация сетевого времени
systemd-udevd.service loaded active running Менеджер событий устройств на основе правил
udisks2.service loaded active running Менеджер дисков
unattended-upgrades.service loaded active running Автоматические обновления
unbound.service loaded active running Сервер DNS Unbound
[email protected] loaded active running Менеджер пользователей для UID 1000
LOAD = Отражает, корректно ли загружен файл определения устройства.
ACTIVE = Высокоуровневое состояние активации устройства, то есть обобщение SUB.
SUB = Низкоуровневое состояние активации устройства, значения зависят от типа устройства.
26 загруженных устройств, перечисленных.
Я считаю, что это те, которые я установил и активировал (и работают как на SuperMicro, так и на Raspberry Pi):
containerd.service loaded active running контейнерная среда выполнения containerd
docker.service loaded active running Контейнерная среда выполнения Docker
prometheus-node-exporter.service loaded active running Экспортер Prometheus для метрик машины
smartmontools.service loaded active running Демон самомониторинга и отчетов (SMART)
unbound.service loaded active running Сервер DNS Unbound
Вещи, которые нужно протестировать:
Проверьте, изменится ли что-то в конфигурацииsudo
безNOPASSWD
.- Отключите установленные службы, которые общие между моим сервером SuperMicro и Raspberry Pi.
Обычно, когда программа отказывается работать в фоновом режиме, это связано с тем, что ей нужен ввод.
Хотя df
на самом деле не читает из stdin, он все же открыт. Попробуйте:
#!/bin/bash
sudo du -h --max-depth=1 / 2> /dev/null 0< /dev/null
Обратите внимание, что это может оставить вас без возможности ввести пароль.
Также возможно, что могут возникнуть проблемы с попыткой отправки соответствующих сигналов в процессе, потому что это не . Я сомневаюсь в этом, но если это так, я бы предложил просто сразу запустить его в фоновом режиме. (Эта проблема у меня отсутствует.)
sudo
ненадежен ;(
Попробуйте
sudo -l
Вы можете обнаружить, что вам нужно остановить sudo
от ожидания tty или пароля, например, создать /etc/sudoers.d/000-defaults
содержащий
Defaults !requiretty, !verifypw, listpw=any
Это поведение по умолчанию. Вы можете избежать приостановки тремя способами
-
Убедитесь, что ни один из stdout, stderr и stdin не подключен к терминалу. Например,
sudo du -h --max-depth=1 / </dev/null 2>/dev/null >>./test.txt
-
Разрешите фоновым процессам работать безпрепятственно. Установите
stty -tostop
перед выполнением кодаstty -tostop sudo du -h --max-depth=1 / >>./test.txt
-
Включите логирование в конфигурации
sudo
.
Информация задокументирована в файлеNEWS
из исходного кода (в Debian):Для
sudo
версии 1.8.22- Когда включено логирование ввода-вывода,
sudo
теперь будет писать в терминал
даже когда оно является фоновым процессом.
Смотрите раздел
I/O LOGGING
вman sudoers
для получения информации о том, как настроить логирование. - Когда включено логирование ввода-вывода,
Ответ или решение
Чтобы ответить на вопрос о "ненадежной проверке фона с использованием bg
в Bash-скрипте с sudo
", необходимо рассмотреть основные аспекты работы с фоновыми процессами и командой sudo
в операционных системах на базе Linux.
Проблема
Вы создали bash-скрипт (test.sh
), который выводит использование дискового пространства в каталогах корневой директории. Скрипт использует команду sudo
для выполнения команды du
с повышенными привилегиями. При этом вы не запрашиваете пароль для sudo
.
Скрипт запускается командой:
./test.sh >> ./test.txt
При его приостановке через комбинацию Ctrl+Z
и попытке возобновить выполнение в фоновом режиме с помощью bg
, вы сталкиваетесь с проблемой: процесс не продолжается в фоновом режиме, несмотря на несколько попыток.
Поведение sudo
в фоновом режиме
Команда sudo
иногда может вести себя непредсказуемо, когда её процесс переводится в фоновый режим. Это связано с несколькими факторами:
-
Взаимодействие с псевдотерминалом:
sudo
может требовать соединения с терминалом для выполнения интерактивных запросов (например, связанных с вводом пароля), даже если ввод пароля отключен. -
Обработка сигналов: Когда скрипт приостанавливается и переводится в фоновый режим,
sudo
продолжает ожидать терминал и может не получать сигналы управления фоновой работой должным образом.
Решения проблемы
-
Перенаправление стандартных потоков: Как было предложено в описании проблемы, можно попробовать перенаправить стандартные потоки
stdin
,stdout
иstderr
, чтобы избежать зависимостей от терминала:sudo du -h --max-depth=1 / < /dev/null 2>/dev/null >> ./test.txt
-
Использование
stty -tostop
: Эта команда отключает стандартное действие остановки фоновым процессом, когда он пытается записывать в терминал:stty -tostop ./test.sh >> ./test.txt
Однако, в описании указано, что этот метод не всегда помогает.
-
Изменение конфигурации
sudo
: В некоторых случаях надо модифицировать конфигурациюsudo
, чтобы отключить запрос пароля и требование терминала. Это можно сделать, добавив в файл/etc/sudoers.d/000-defaults
:Defaults !requiretty, !verifypw, listpw=any
-
Запуск без
sudo
в скрипте: Самый эффективный способ обойти проблему — это запускать весь скрипт сsudo
, а не включать его непосредственно в скрипт. Это важный аспект, так как в этом случаеbg
иfg
работают как ожидается.sudo ./test.sh >> ./test.txt
Заключение
Каждый из предложенных способов может помочь, однако некоторые из них могут не срабатывать в определенных случаях, что было упомянуто в вашем описании. Важно тестировать различные подходы, адаптируя их к обстоятельствам и особенностям вашей системы.
При правильной конфигурации и понимании работы sudo
, управление фоновыми процессами становится более предсказуемым и надежным. Советую провести эксперименты с вышеописанными способами и, при необходимости, изучить конфигурацию вашей среды для поиска дополнительных решений.