Как определить рабочую среду в bash-скрипте?

Вопрос или проблема

Я пишу скрипт на bash, который должен знать, какая среда рабочего стола (XFCE, Unity, KDE, LXDE, Mate, Cinnamon, GNOME2, GNOME3 и т. д.) запущена.

Как я могу получить эту информацию?

Основная проблема при проверке DESKTOP_SESSION заключается в том, что она устанавливается менеджером дисплея, а не сессией рабочего стола и подвержена несоответствиям. Для lightdm на Debian значения берутся из имен файлов в /usr/share/xsessions/. DESKTOP_SESSION отражает среду рабочего стола, если на входе сделан определенный выбор, однако lightdm-xsession всегда используется по умолчанию.

GDMSESSION — это другой вариант, но, похоже, у него такая же проблема (это то же значение, что и DESKTOP_SESSION для меня).

XDG_CURRENT_DESKTOP выглядит как хороший выбор, однако в настоящее время он не входит в стандарт XDG и, следовательно, не всегда реализован. См. здесь для обсуждения этого вопроса. Этот ответ показывает его значения для различных дистрибутивов/рабочих столов, я также могу подтвердить, что он в настоящее время недоступен для меня в XFCE.

Разумным запасным вариантом, если XDG_CURRENT_DESKTOP не существует, было бы попытаться использовать XDG_DATA_DIRS. Если файлы данных для среды рабочего стола установлены в директории с ее именем, этот подход должен сработать. Надеюсь, это будет актуально для всех дистрибутивов/рабочих столов!

Следующий (с GNU grep) тестирует XFCE, KDE и Gnome:

echo "$XDG_DATA_DIRS" | grep -Eo 'xfce|kde|gnome'

Совместимо с POSIX:

echo "$XDG_DATA_DIRS" | sed 's/.*\(xfce\|kde\|gnome\).*/\1/'

Чтобы объединить с проверкой XDG_CURRENT_DESKTOP:

if [ "$XDG_CURRENT_DESKTOP" = "" ]
then
  desktop=$(echo "$XDG_DATA_DIRS" | sed 's/.*\(xfce\|kde\|gnome\).*/\1/')
else
  desktop=$XDG_CURRENT_DESKTOP
fi

desktop=${desktop,,}  # преобразовать в строчные буквы
echo "$desktop"

Метод #1 – $DESKTOP_SESSION

Я думаю, вы можете узнать, опросив переменную окружения $DESKTOP_SESSION. Я не совсем уверен, насколько широко это поддерживается, но в моем ограниченном тестировании это оказалось доступным на Fedora и Ubuntu.

$ echo $DESKTOP_SESSION
gnome

Другой вариант – переменная $XDG_SESSION_DESKTOP.

Метод #2 – wmctrl

Существует также этот метод, который использует wmctrl.

$ wmctrl  -m
Name: GNOME Shell
Class: N/A
PID: N/A
Режим "показать рабочий стол" менеджера окон: N/A

Ссылки

Вы можете использовать этот скрипт bash. Он может обнаружить имя и версию среды рабочего стола.

#!/bin/bash

function detect_gnome()
{
    ps -e | grep -E '^.* gnome-session$' > /dev/null
    if [ $? -ne 0 ];
    then
    return 0
    fi
    VERSION=`gnome-session --version | awk '{print $2}'`
    DESKTOP="GNOME"
    return 1
}

function detect_kde()
{
    ps -e | grep -E '^.* kded4$' > /dev/null
    if [ $? -ne 0 ];
    then
        return 0
    else    
        VERSION=`kded4 --version | grep -m 1 'KDE' | awk -F ':' '{print $2}' | awk '{print $1}'`
        DESKTOP="KDE"
        return 1
    fi
}

function detect_unity()
{
    ps -e | grep -E 'unity-panel' > /dev/null
    if [ $? -ne 0 ];
    then
    return 0
    fi
    VERSION=`unity --version | awk '{print $2}'`
    DESKTOP="UNITY"
    return 1
}

function detect_xfce()
{
    ps -e | grep -E '^.* xfce4-session$' > /dev/null
    if [ $? -ne 0 ];
    then
    return 0
    fi
    VERSION=`xfce4-session --version | grep xfce4-session | awk '{print $2}'`
    DESKTOP="XFCE"
    return 1
}

function detect_cinnamon()
{
    ps -e | grep -E '^.* cinnamon$' > /dev/null
    if [ $? -ne 0 ];
    then
    return 0
    fi
    VERSION=`cinnamon --version | awk '{print $2}'`
    DESKTOP="CINNAMON"
    return 1
}

function detect_mate()
{
    ps -e | grep -E '^.* mate-panel$' > /dev/null
    if [ $? -ne 0 ];
    then
    return 0
    fi
    VERSION=`mate-about --version | awk '{print $4}'`
    DESKTOP="MATE"
    return 1
}

function detect_lxde()
{
    ps -e | grep -E '^.* lxsession$' > /dev/null
    if [ $? -ne 0 ];
    then
    return 0
    fi

    # Мы можем обнаружить версию LXDE только через менеджер пакетов
    which apt-cache > /dev/null 2> /dev/null
    if [ $? -ne 0 ];
    then
    which yum > /dev/null 2> /dev/null
    if [ $? -ne 0 ];
    then
        VERSION='UNKNOWN'
    else
        # Для Fedora
        VERSION=`yum list lxde-common | grep lxde-common | awk '{print $2}' | awk -F '-' '{print $1}'`
    fi
    else    
    # Для Lubuntu и Knoppix
    VERSION=`apt-cache show lxde-common /| grep 'Version:' | awk '{print $2}' | awk -F '-' '{print $1}'`
    fi
    DESKTOP="LXDE"
    return 1
}

function detect_sugar()
{
    if [ "$DESKTOP_SESSION" == "sugar" ];
    then
    VERSION=`python -c "from jarabe import config; print config.version"`
    DESKTOP="SUGAR"
    else
    return 0
    fi
}

DESKTOP="UNKNOWN"
if detect_unity;
then
    if detect_kde;
    then
    if detect_gnome;
    then
        if detect_xfce;
        then
        if detect_cinnamon;
        then
            if detect_mate;
            then
            if detect_lxde;
            then
                detect_sugar
            fi
            fi
        fi
        fi
    fi
    fi
fi

if [ "$1" == '-v' ];
then
    echo $VERSION
else
    if [ "$1" == '-n' ];
    then
    echo $DESKTOP
    else
    echo $DESKTOP $VERSION
    fi
fi

Стандарты сильно изменились с момента, когда вопрос был задан в 2014 году.

На 2021 год, моя рекомендация такова: используйте только официальную $XDG_CURRENT_DESKTOP.

Будьте осторожны, поскольку официально это разделенный двоеточием список (как $PATH), так что не предполагается, что он содержит только одно значение, даже если это так в большинстве DE. Например, в Unity от Ubuntu он установлен на Unity:Unity7:ubuntu.

Если вы предпочитаете обрабатывать одно значение, используйте $XDG_SESSION_DESKTOP.

Официальные стандарты:

Другие связанные переменные окружения теперь следует считать устаревшими.

Функция bash, которая правильно проверяет заданную строку относительно текущей среды рабочего стола:

# Инкапсулирует беспорядок, которым была, есть или когда-либо будет детекция DE...
# Без аргументов проверяет, есть ли вообще среда рабочего стола
# Подсистема сделана намеренно, чтобы нам не нужно было сохранять/восстанавливать IFS
# Сравнение без учета регистра
is_desktop_environment() (
    local de=${1:-}
    local DEs=${XDG_CURRENT_DESKTOP:-}

    # Упрощение: если de пусто, проверьте, пустое ли DEs
    if [[ -z "$de" ]]; then if [[ "$DEs" ]]; then return; else return 1; fi; fi

    # Приведите оба к нижнему регистру
    de=${de,,}; DEs=${DEs,,}

    # Проверьте de с каждым компонентом DEs
    IFS=:; for DE in $DEs; do if [[ "$de" == "$DE" ]]; then return; fi; done

    # Не найдено
    return 1
)

Тестирование:

for de in "" Ubuntu Gnome KDE Unity; do
    if is_desktop_environment "$de"; then
        echo "Да, это ${de:-DE}"
    else
        echo "Нет, это не ${de:-DE}"
    fi
done

Да, это DE
Да, это Ubuntu
Нет, это не Gnome
Нет, это не KDE
Да, это Unity

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

Если это не так, то я полагаю, вам придется проверять каждую среду рабочего стола, которую вы хотите идентифицировать. Все они должны вводить свои собственные переменные окружения.

Если переменная окружения XDG_CURRENT_DESKTOP доступна, она должна сообщить вам.

# echo $XDG_CURRENT_DESKTOP
KDE

Вы можете искать выполняющиеся процессы Xorg. Родитель этого процесса должен быть вашим менеджером дисплея. Его потомки должны дать представление о том, какая среда рабочего стола запущена. В моей системе менеджер дисплея выполняет себя (с разными параметрами). Это затем порождает x-session-manager, который связан с xfce4-session. Этого может быть достаточно, но все дочерние процессы связаны с моей средой рабочего стола. Находить их через дерево процессов — это лучший способ исключить элементы других оконных систем, запущенных различными программами (или, возможно, намеренно).

Моя первая мысль заключалась в том, что лучше всего искать менеджер окон, связанный с вашей средой рабочего стола, но часто можно настроить запуск другого (например, xmonad в Gnome), так что это не надежно. Наверное, лучше всего искать тот, который управляет фактическим рабочим столом, например, xfdesktop или любой другой элемент, который вам действительно нужен для работы вашего скрипта 🙂

Пример

Вот пример использования procps-ng (-C и --ppid не являются POSIX). Он предполагает, что имеется только один экземпляр Xorg.

Это просто пример, который работает для рабочего стола xfce. Полный рабочий пример требует исследования процессов, используемых каждой системой рабочего стола, так же как и большинство других решений требует исследования того, как устанавливаются переменные окружения в различных других системах рабочего стола.

X=Xorg

search_descendants ()
{
  ps h -o comm --ppid $1 |
    grep -E '^(xfdesktop|another_desktop_process)$' &&
    return 0

  for pid in $(ps h -o pid --ppid $1)
  do
    search_descendants $pid && return 0
  done

  return 1
}

dm_pid=$(ps h -o ppid -C "$X")

case "$(search_descendants $dm_pid)" in
  xfdesktop)
    desktop=xfce
    ;;
  another_desktop_process)
    desktop=another_desktop
    ;;
  *)
    desktop=unknown
    ;;
esac

echo $desktop

После всех проведенных экспериментов, о которых сообщалось в многочисленных комментариях, я считаю своим долгом как ОП прийти к консенсусному ответу. (Не сомневайтесь, я был бы рад пересмотреть этот ответ, если появятся контрастные данные.)

На данный момент, похоже, лучше всего опираться на $XDG_CURRENT_DESKTOP, когда эта переменная определена. Если нет, $XDG_DATA_DIRS может предоставить желаемую информацию, больше чем первая буква ${DESKTOP_SESSION:0:1}.

Это работает как на Ubuntu 18.10 (cosmic) [тип lxqt], так и на Mint 19 (tara) [тип cinnamon]:

$  set | grep XDG_CURRENT_DESKTOP | tr '[:upper:]' '[:lower:]' | cut -d'=' -f2

Захватите результат в переменную и выполните дальнейший необходимый код с помощью аналитической логики (инструкция case, if/then), которая включает любые/все распознанные типы, начиная с этого; и/или функционируйте корректно, когда используются незнакомые типы.

Ответ или решение

Определение окружения рабочего стола в bash-скрипте

При написании bash-скрипта, который нуждается в идентификации текущего окружения рабочего стола (например, XFCE, Unity, KDE, LXDE, Mate, Cinnamon и так далее), часто возникает необходимость обратиться к переменным окружения. Однако, не все версии различных дистрибутивов Linux поддерживают одни и те же переменные. В данном ответе я рассмотрю наиболее распространенные подходы к определению рабочего окружения и предложу пример скрипта для их использования.

Основные переменные окружения

  1. XDG_CURRENT_DESKTOP: Это наиболее предпочтительная переменная, так как она предназначена для обозначения текущего окружения рабочего стола согласно стандартам Freedesktop.org. Однако, будьте внимательны: в некоторых дистрибутивах она может не поддерживаться или содержать список значений, разделенных двоеточием.

    echo "$XDG_CURRENT_DESKTOP"
  2. DESKTOP_SESSION и XDG_SESSION_DESKTOP: Эти переменные также могут давать информацию о текущем сеансе рабочего стола. Однако, как вы правильно заметили, они являются более подверженными изменениям и могут не всегда точно отражать текущее окружение.

    echo "$DESKTOP_SESSION"
    echo "$XDG_SESSION_DESKTOP"
  3. XDG_DATA_DIRS: Если переменная XDG_CURRENT_DESKTOP недоступна, вы можете обращаться к XDG_DATA_DIRS для выдачи информации о доступных управляющих файлах для различных окружений.

  4. wmctrl: Этот инструмент может быть использован для получения информации о запущенных сеансах рабочего окружения.

    wmctrl -m

Пример скрипта

Вот пример bash-скрипта, который использует перечисленные переменные для определения текущего окружения рабочего стола:

#!/bin/bash

detect_desktop_environment() {
    local desktop=""

    # Проверяем XDG_CURRENT_DESKTOP
    if [ -n "$XDG_CURRENT_DESKTOP" ]; then
        desktop="$XDG_CURRENT_DESKTOP"
    # Падбораем значение из XDG_DATA_DIRS, если предыдущая переменная недоступна
    else
        desktop=$(echo "$XDG_DATA_DIRS" | grep -Eo 'xfce|kde|gnome|unity|mate|cinnamon' | head -n 1)
    fi

    # Приводим к нижнему регистру
    desktop=${desktop,,}

    # Выводим результат
    echo "Текущее окружение рабочего стола: $desktop"
}

# Вызов функции
detect_desktop_environment

Советы по улучшению

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

    ps -e | grep -E 'xfce4-session|gnome-session|kded4|cinnamon'
  2. Пользовательские функции: Создайте функции для проверки конкретных окружений рабочего стола, как показано в более сложных примерах.

  3. Обработка ошибок и исключений: Убедитесь, что ваш скрипт корректно обрабатывает ситуации, когда ни одна из переменных не установлена.

Заключение

В итоге, для определения окружения рабочего стола в bash-скрипте лучше всего использовать переменную XDG_CURRENT_DESKTOP, если она доступна. Если нет — можно обратиться к переменной XDG_DATA_DIRS или использовать команду wmctrl для получения информации о текущем рабочем окружении. Подходы должны быть проверены в зависимости от конкретной конфигурации и использования дистрибутива.

Оцените материал
Добавить комментарий

Капча загружается...