Комментарии 22
Ох уж эти админы, никак свой паппет настроить не могут!
MATE_PID=$(pgrep mate-session -u $USER)
DBUS_ADDR=$(cat /proc/$MATE_PID/environ |grep -z "^DBUS_SESSION_BUS_ADDRESS=")
А симптомы были те же — всё работает из консоли, но совсем не работает из крона.
Самое время узнать про существование -z флага у grep. Спасибо!
В прошлый раз, когда мы использовали этот флаг в сочетании с -E (с -P оно даже в тот момент не работало), оно сломалось после обновления grep и после этого у нас nginx перестал отдавать большие ответы от php-fpm, если ты помнишь :).
tr '\0' '\n' < /proc/10684/environ | fgrep SUDO_USER
Ну или как вам уже подсказали, так:
grep -Fz SUDO_USER /proc/10684/environ
И ещё какая-то странная идея экранировать всё подряд, да ещё и двойными кавычками. Если уж использовать кавычки «на всякий случай», надо использовать одинарные, в них интерполяции нет. Строка из комментария выше:
DBUS_ADDR=$(grep -z ^DBUS_SESSION_BUS_ADDRESS= /proc/$MATE_PID/environ)
«Бесполезная кошка» (useless cat) — антипаттерн в шеллах, не надо его использовать.
cat /proc/self/environ| tr '\0' '\n' | grep 'SOMETHING'
использовать
strings -a /proc/self/environ | grep 'SOMETHING'
А что в бесполезной кошке плохо?
Используя fgrep и чтение из файла мы делаем совсем не по unix-way, и одна программа делает не одно действие. Для написания шелл-скриптов убирать кошек верно, это и оптимизация, и выразительность. Но при работе из командной строки смысла в этом не вижу.
Возвращаясь к нашим баранам — (f)grep ищёт что-то в файле/потоке — и неважно откуда этот поток берется — из cat или напрямую из файла, к тому же, без операции чтения тут не обойтись в принципе. Если программа в состоянии читать файл напрямую — ничего плохого в этом нет, даже наоборот, и она всё ещё выполняет только одну функцию — поиск.
При работе из командной строки это как минимум печатать лишние символы, а вообще (к вопросу о том что плохо в бесполезной кошке) — как это ни удивительно, но это просто бесполезное дополнительное действие и неразумная трата системных ресурсов — создается дополнительный процесс, под него выделяется память, файловые дескрипторы etc — куча дополнительных накладных расходов. Да, на почти любой современной системе это практически незаметно, особенно если не выполняется 1000 раз в секунду — но — зачем?
И наконец… unix-way — это не догма, не закон и даже не правило, и совсем не отменяет здравого смысла, далеко не всегда имеет смысл сохранять философию «одна программа — одна функция», по соображениям эффективности, целостности и много ещё каким, но это тема для целой статьи…
Просто если буквально следовать этому, то вместо опций, модифицирующих поведение программ (иногда очень существенно) у нас будет одна программа на каждый вариант поведения/обработки, и придётся их комбинировать для достижения одной функции (причём не факт что позволит достичь результата за один проход) — это разве разумно?
А с третьей, когда необходимо обработать или удалить парочку сотен тысяч файлов в конкретной директории, то только find и спасает, ибо он применяет -delete (-exec) в цикле по мере нахождения файлов, а все остальные команды (типа rm dir/*
, some_command dir/*
, etc) вначале пытаются распаковать список аргументов, на чем благополучно зависают.
Ну почему, xargs вроде бы тоже так работает — он накапливает буфер для того количества аргументов, которые вы передали, или что-то около 5000 по умолчанию.
ls -l /proc/$pid/{exe,cwd}
покажут сразу и «настоящий» экзешник и текущий cwd (который часто тот который был в момент запуска, хотя и не всегда), без шаманства с переменными среды.К тому же, переменные среды могут быть не совсем верными, а ps покажет то что захочет сам процесс.
bash -l
кроме того, что часто чинит env-переменные (отчего в неё любят заворачивать cron-задачи), может и ломать. Лет 5 назад, когда RHEL 7 только появился, а контейнеризация ещё не была так популярна, один заказчик выдал нам пачку виртуалок на RHEL 7 с какими-то приблудами безопасности, на которые вы водрузили разрабатываемый нами веб-портал с помощью паппетов, кривых рук и такой-то матери. В том числе в комплекте была cron-задача, запускавшаяся каждую минуту. Каждый примерно месяц (с поразительной периодичностью) виртуальные машины зависали намертво. Оказывается, что-то там (память, к сожалению, не сохранила, что именно), реагировало на каждый логин в систему и на 65536-м логине вешало всё к чёрту. Убирание bash -l
обёртки из crontab'а решало проблему (точнее, делало её крайне редкой). Такая вот прохладная история.
Уже откройте для себя systemd.timers. Там еще 100500 удобных вещей, которые можно делать без баш-портянок. И такой проблемы, как "я запустил руками — работает, а по крону — не работает" не стоит впринципе.
alexxz@bi1.mlan:~> sudo systemd-run --on-active=1 /bin/sh -c 'env > /tmp/foo'
Running timer as unit run-r5f95073d0d5a4874832429b0b4168aa5.timer.
Will run service as unit run-r5f95073d0d5a4874832429b0b4168aa5.service.
alexxz@bi1.mlan:~> cat /tmp/foo | tr '\0' '\n'
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
SHLVL=1
LC_CTYPE=en_US.UTF-8
_=/usr/bin/env
Я вижу всё такое же неполное окружение, как из крона. Лишь только самую малость получше.
Вы немного не поняли. С systemd.timer вы настраиваете юнит, прописывая всё необходимое окружение.
После этого не имеет значение как и кем этот юнит будет запущен — вами ( systemctl start ) или планировщиком — всё будет выполнено в фиксированном, одинаковом окружении.
Более того, с кроном есть еще одна очень гадкая проблема, которая обнаружется потом, когда вы будете думать, что всё работает: например, скрипт в кроне делает какие-либо операции, создавая для себя каталоги/файлы. Вы дёрнули этот скрипт из-под другого юзера, а хуже — из-под рута, скрипт создал каталоги с соотв. владельцем. Всё работает корректно, вы радостно идёте домой. Вот только при следующем запуске ваш скрипт обломает зубки, тк прав доступа ему уже не хватит.
И этой пробемы снова нет с systemd.timer'ами. И там еще куча полезного.
Но двайте я подслащу хейтерам системд: есть там недостаток, довольно непрятный. Без костылей там нет нормальных почтовых уведомлений о проблемах с запуском юнита, как это есть в cron. Увы и ах. Однако, при всей моей любви к крону, я вижу кучу профита у timer'ов и выбираю их.
Как дебажить переменные окружения в Linux