Как я могу выполнить локальную команду (для запуска скрипта) при (непосредственно перед) выходе из сеанса Unity?

На риск размещения дублирующего вопроса:

Как я могу запустить локальный скрипт (как текущий пользователь) при выходе?

Я прочитал (и попробовал) среди других:

  1. Этот (версия Мартона), который совершенно ничего не делал, использовался в простом сценарии, создающем файл, абсолютные пути к сценарию (будучи исполняемым) и к файлу.
  2. Этот, который должен быть устаревшим; это заставило меня удалить файл из командной строки, чтобы иметь возможность снова использовать мою систему.
  3. Я также посмотрел на это, без успеха.

Я полагаю, что я, должно быть, делаю что-то не так, но не могу понять, в чем моя слепая зона

контекст

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

Поэтому скрипт должен запускаться при выходе из системы, чтобы получить расположение, очевидно, запускаемое текущим пользователем.

1 ответ

Решение

Основная теория

Как вы можете знать или не знать, многие действия Unity реализованы с использованием dbus. Большим преимуществом dbus является то, что вы можете выполнять множество необходимых действий с правами root, вызывая соответствующие методы в командной строке без необходимости иметь учетную запись администратора, например, закрывая вашу систему.

Именно в нашем случае нас интересует com.canonical.Unity оказание услуг, /com/canonical/Unity/Session дорожка. Вы можете перечислить информацию об этом с qdbus команда. Особенно нас интересуют сигналы, которые имеют Requested в них.

$ qdbus com.canonical.Unity /com/canonical/Unity/Session | grep 'signal.*Requested.*'                             
signal void com.canonical.Unity.Session.LockRequested()
signal void com.canonical.Unity.Session.LogoutRequested(bool have_inhibitors)
signal void com.canonical.Unity.Session.RebootRequested(bool have_inhibitors)
signal void com.canonical.Unity.Session.ShutdownRequested(bool have_inhibitors)
signal void com.canonical.Unity.Session.UnlockRequested()

Эти сигналы появляются в шине, когда пользователь щелкает по любому из пунктов выключения, блокировки, выхода из системы или перезагрузки в раскрывающемся меню сеанса в правой части верхней панели Unity. Итак, что нам нужно сделать, это:

  • контролировать шину для появления этих сигналов.
  • как только они появятся - выполните определенное действие.

Конечно, большой недостаток заключается в том, что если пользователь использует sudo shutdown -P now или же gnome-session-quit это не будет сказано dbus так что, какие бы действия ни требовались, они не будут выполнены.

Мониторинг dbus

Удобно, есть команда для этого, dbus-monitor и мы можем отфильтровать его вывод, используя набор параметров, и выполнить действие над ним, используя while read do … done состав

Ниже приведен пример простого сценария мониторинга.

dbus-monitor --profile "interface='com.canonical.Unity.Session',type=signal" | \
while read -r line;
do
  echo "$line" 
  sleep 0.25
done

Он просто контролирует шину на наличие сигналов и возвращает их обратно на стандартный вывод, если они появляются; Конечно, эхо может быть любой командой. Запустите его и попробуйте нажать на каждый пункт в меню сеанса, который должен генерировать сигналы, и вы должны увидеть что-то вроде этого:

$ ./logout_monitor.sh                                                                                             
sig 1458319246  172587  2   /org/freedesktop/DBus   org.freedesktop.DBus    NameAcquired
sig 1458319251  213766  5496    /com/canonical/Unity/Session    com.canonical.Unity.Session RebootRequested
sig 1458319265  62555   5525    /com/canonical/Unity/Session    com.canonical.Unity.Session LogoutRequested
sig 1458319271  856770  5555    /com/canonical/Unity/Session    com.canonical.Unity.Session LockRequested
sig 1458319273  223940  5564    /com/canonical/Unity/Session    com.canonical.Unity.Session Locked
sig 1458319276  991413  5604    /com/canonical/Unity/Session    com.canonical.Unity.Session UnlockRequested
sig 1458319278  3443    5606    /com/canonical/Unity/Session    com.canonical.Unity.Session Unlocked

Итак, теперь у нас есть функция мониторинга, которая может выполнять действие, когда происходит прерывание. Теперь, чтобы ответить на конкретный вопрос, который вы пытались решить, ваш сценарий делает снимки значков на рабочем столе. Нет никакого вреда, если мы делаем снимок каждый раз, когда появляется сигнал - его не нужно специально перезагружать или выключать. Поэтому, если мы будем отслеживать этот конкретный интерфейс Unity на наличие сигналов и делать снимки при поступлении каждого сигнала, мы можем упростить сценарии.

Сценарий, управляемый прерываниями

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

#!/bin/bash

main()
{
  ARG="cow"
  dbus-monitor --profile "interface='com.canonical.Unity.Session',type=signal" | 
  while read -r line;
  do
    grep -q '.*NameAcquired.*' <<< "$line"  && continue  #  Ignore that first line
    if [ -n "$line"  ];then
       interrupt $ARG # call your python snapshot script here
    fi
  done
}

interrupt()
{
  echo 'Old McDonald had a ' $ARG ' e-i-e-i-o '
}

main

ПРИМЕЧАНИЕ: Dbus полагается на сеанс GUI, поскольку (насколько я знаю) он начинается с входа в Unity/Gnome. В более старых средах, таких как blackbox и openbox, а также в средах TTY, сеанс dbus не запускается, поэтому этот сценарий будет прерван, если вы попытаетесь запустить его в ~/.profile (У меня был один пользователь, который пытался сделать что-то подобное, и он попал в беду). Запустите такой скрипт, используя программу запуска приложений Unity или Gnome.

Выходя за рамки этого сценария

  • У Dbus много API, включая Python
  • Я предпочитаю использовать qdbus потому что это просто, но всегда можно использовать dbus-send, Примеры
  • Функция прерывания может быть любой, даже другой dbus методы. Там есть что посмотреть.

Общая информация: я использовал этот же метод для предотвращения выключения, если работает apt

Другие вопросы по тегам