Получение PID от фонового процесса, запускаемого от имени другого пользователя

#bash #pid #su

#bash #pid #su

Вопрос:

Получить идентификатор фонового процесса легко из командной строки, перейдя:

 $ my_daemon amp;
$ echo $!
  

Но что, если я хочу запустить его от имени другого пользователя, например:

 su - joe -c "/path/to/my_daemon amp;;"
  

Теперь, как я могу получить PID my_daemon?

Комментарии:

1. Для меня это выглядит вполне по теме для SO; это вопрос о программировании оболочки, и как таковой входит в компетенцию SO.

Ответ №1:

Кратко — с большой долей сложности.

Вы должны организовать, чтобы оболочка su’d записывала дочерний PID в файл, а затем выбирала выходные данные. Учитывая, что файл будет создавать ‘joe’, а не ‘dex’, это добавляет еще один уровень сложности.

Вероятно, самым простым решением является:

 su - joe -c "/path/to/my_daemon amp; echo $! > /tmp/su.joe.$$"
bg=$(</tmp/su.joe.$$)
rm -f /tmp/su.joe.$$   # Probably fails - joe owns it, dex does not
  

Следующее решение включает использование запасного файлового дескриптора под номером 3.

 su - joe -c "/path/to/my_daemon 3>amp;- amp; echo $! 1>amp;3" 3>/tmp/su.joe.$$
bg=$(</tmp/su.joe.$$)
rm -f /tmp/su.joe.$$
  

Если вы беспокоитесь о прерываниях и т.д. (И, вероятно, так и должно быть), То вы тоже загоняете вещи в ловушку:

 tmp=/tmp/su.joe.$$
trap "rm -f $tmp; exit 1" 0 1 2 3 13 15
su - joe -c "/path/to/my_daemon 3>amp;- amp; echo $! 1>amp;3" 3>$tmp
bg=$(<$tmp)
rm -f $tmp
trap 0 1 2 3 13 15
  

(Перехваченными сигналами являются HUP, INT, QUIT, PIPE и TERM — плюс 0 для выхода из оболочки.)

Предупреждение: хорошая теория — непроверенный код…

Комментарии:

1. Потрясающий ответ. Я мог бы обойтись только этим: su - joe -c "/path/to/my_daemon amp; echo $! > /tmp/su.joe.$$" экранирование $! и отсутствие точки с запятой после my_daemon amp; , безусловно, тоже является ошибкой. Я собираюсь немного с этим поиграть.

2. Не забудьте добавить пробел после $! или оболочка может интерпретировать это странно.

Ответ №2:

Представленные здесь подходы у меня не сработали. Вот что я сделал:

 PID_FILE=/tmp/service_pid_file
su -m $SERVICE_USER -s /bin/bash -c "/path/to/executable $ARGS >/dev/null 2>amp;1 amp; echo $! >$PID_FILE"
PID=`cat $PID_FILE`
  

Ответ №3:

Пока выходные данные фонового процесса перенаправляются, вы можете отправить PID в стандартный вывод:

 su "${user}" -c "${executable} > '${log_file}' 2>amp;1 amp; echo $!"
  

Затем PID может быть перенаправлен в файл, принадлежащий первому пользователю, а не второму пользователю.

 su "${user}" -c "${executable} > '${log_file}' 2>amp;1 amp; echo $!" > "${pid_file}"
  

Однако файлы журнала должны принадлежать второму пользователю, чтобы сделать это таким образом.

Ответ №4:

Вот мое решение

 su oracle -c "/home/oracle/database/runInstaller" amp;
pid=$(pgrep -P $!)
  

Эксплантация

  • pgrep -P $! — Получает дочерний процесс родительского pid $!

Комментарии:

1. Почему это отклонено? Две строки сжатого кода без использования tmp-файлов.

Ответ №5:

Я использовал вышеупомянутое решение в Linux, но мне пришлось добавить режим ожидания, чтобы дать дочернему процессу возможность запуститься.

 su - joe -c "/path/to/my_daemon > /some/output/file" amp;
parent=$!
sleep 1
pid=$(pgrep -P $parent)
  

Запуск в bash, ему не нравится, pid=$(pgrep -P $!) но если я добавлю пробел после ! , все будет в порядке: pid=$(pgrep -P $! ) . Я использовал дополнительную $parent переменную, чтобы напомнить себе, что я делаю, когда в следующий раз посмотрю на скрипт.