Linux получить имена мониторов

Ситуация: я использую несколько мониторов и хочу получить их имена в bash. В настоящее время я использую Ubuntu 10.04.

Я знаю про xrandr. Из него я могу получить только данные статистики. Я хочу прочитать все имена мониторов в массиве, чтобы работать с ними.

Есть ли четкий способ сделать это, не вырезая имена из какой-то строки? Ясным способом было бы чтение их из файла. Непонятным способом было бы направить вывод xrandr в какую-то функцию, чтобы вырезать из него имена.


person Jānis Gruzis    schedule 08.05.2012    source источник
comment
Насколько я знаю, вам нужно получить это из конкретных API-интерфейсов драйвера. Раньше было что-то в nvidia. Какая у тебя карта? Или нужно было что-то универсальное?   -  person Miquel    schedule 08.05.2012
comment
@Miquel Моя видеокарта - ATI Radeon HD 5000. Конечно, лучше было бы получить более универсальное решение. Но подойдет и конкретное решение для моей текущей машины.   -  person Jānis Gruzis    schedule 08.05.2012
comment
Я согласен с тем, что получение определенных свойств путем анализа и декодирования вывода xrandr --prop или xrandr --verbose не является очевидным способом, поскольку форматирование вывода xrandr может быть изменено и недокументировано. Я бы хотел, чтобы у xrandr были способы чтения отдельных свойств данного вывода (например, как у exiftool есть способы чтения отдельных тегов метаинформации заданных файлов).   -  person jarno    schedule 05.04.2015
comment
Я не уверен, какие имена мониторов вам нужны. Достаточно ли будет получить выходные имена? Я заметил, что информация EDID портативного компьютера может не иметь имени монитора для встроенного дисплея, но в любом случае может быть заявлено какое-то название бренда и название детали.   -  person jarno    schedule 05.04.2015
comment
Аналогичная тема есть в unix. .stackexchange.com.   -  person pevik    schedule 22.05.2015


Ответы (7)


sudo get-edid мне не помогло. (EDIT: теперь работает на другом компьютере, Lubuntu 14.10; я бы обвинил различия в BIOS, но это случайное предположение...)

В любом случае под X xrandr --verbose печатает блок EDID. Вот быстрый и грязный способ извлечь его и передать parse-edid:

#!/bin/bash
xrandr --verbose | perl -ne '
if ((/EDID(_DATA)?:/.../:/) && !/:/) {
  s/^\s+//;
  chomp;
  $hex .= $_;
} elsif ($hex) {
  # Use "|strings" if you dont have read-edid package installed 
  # and just want to see (or grep) the human-readable parts.
  open FH, "|parse-edid"; 
  print FH pack("H*", $hex); 
  $hex = "";
}'
person Beni Cherniavsky-Paskin    schedule 15.08.2013
comment
Для карт Intel файлы edid находятся в /sys. find /sys -name edid. Похоже, это не относится к ATI. Не могу проверить для NVidia. - person Dave; 07.06.2014
comment
Для xrandr в Ubuntu 12.04 замените EDID: на EDID_DATA: в строке 3. Он отлично работает, когда используется |strings, согласно комментарию в коде. - person MestreLion; 24.07.2014
comment
Я обнаружил, что xrandr знает текущий EDID лучше, чем файл, найденный командой @Dave, если вы меняете монитор на лету. - person jarno; 01.04.2015

Вдохновленный ответом Бени, он будет читать данные EDID с использованием xrandr и извлекать имена мониторов в соответствии с спецификации EDID без необходимости каких-либо внешних такие инструменты, как parse-edid:

#!/bin/bash
while read -r output hex conn; do
    [[ -z "$conn" ]] && conn=${output%%-*}
    echo "# $output $conn   $(xxd -r -p <<< "$hex")"
done < <(xrandr --prop | awk '
    !/^[ \t]/ {
        if (output && hex) print output, hex, conn
        output=$1
        hex=""
    }
    /ConnectorType:/ {conn=$2}
    /[:.]/ && h {
        sub(/.*000000fc00/, "", hex)
        hex = substr(hex, 0, 26) "0a"
        sub(/0a.*/, "", hex)
        h=0
    }
    h {sub(/[ \t]+/, ""); hex = hex $0}
    /EDID.*:/ {h=1}
    END {if (output && hex) print output, hex, conn}
    ' | sort
)

Использует awk для точного извлечения имени монитора только и без лишнего мусора из EDID, поэтому магические числа, такие как 000000fc00, 26 и 0a. Наконец, использует xxd для преобразования из шестнадцатеричного в ASCII, печатая одно имя монитора в строке.

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

$ monitor-switch --list
Connected monitors:
# DFP5  HDMI    HT-R391
# DFP7  DVI-I   DELL U2412M

$ monitor-switch --list
Connected monitors:
# DisplayPort-1 DisplayPort DELL U2412M
# DisplayPort-3 DisplayPort DELL U2415
# HDMI-A-2      HDMI        LG TV
person MestreLion    schedule 24.07.2014
comment
Я проверил встроенный скрипт на своем мониторе, и он ничего не печатает. Я проверил EDID и заметил, что в нем есть два дескриптора монитора, помеченные как FCh, первый из которых — L1715S, а второй — пустой. На моем ноутбуке нет такого дескриптора для встроенного дисплея, но есть два дескриптора, помеченных как FEh, которые, по-видимому, содержат торговую марку CPT и название модели CLAA102NA0A. - person jarno; 02.04.2015
comment
По крайней мере, одна запись FCh является обязательной по спецификации, поэтому странно, что ваш ноутбук не содержит ее ... FEh означает неопределенный текст, в основном свободное текстовое поле, поэтому я не могу полагаться на то, что он содержит соответствующую информацию. Чтобы ничего не печатать, откройте вопрос, вставив оба EDID, чтобы мы могли настроить сценарий для вашего случая. - person MestreLion; 03.04.2015
comment
Возможно, у дисплея ноутбука нет названия, поскольку он не является отдельным потребительским продуктом. - person jarno; 03.04.2015
comment
У моего другого ноутбука то же самое: торговая марка монитора находится в первом дескрипторе, а название детали — во втором дескрипторе, оба помечены FEh. - person jarno; 03.04.2015
comment
Пара реальных образцов EDID для тестирования: 00ffffffffffff001e6d6f432c340400110f01036e221b78ea2ee5a4574a9c25115054a56b80314f454f614f81800101010101010101302a009851002a4030701300520e1100001e000000fd00384b1e530e000a202020202020000000fc004c31373135530a202020202020000000fc000a2020202020202020202020200098, 00ffffffffffff00320c000000000000000f0102801e16780a74b09657548b282550540000000101010101010101010101010101010164190040410026301888360030e410000018000000000000000000000000000000000000000000fe004c475068696c6970734c43440a000000fe004c503135305830382d544c414100a3 - person jarno; 03.04.2015
comment
На самом деле, я сделал сценарий, который выводит поле имени (имен) монитора и поле (поля) данных, когда один или несколько EDID в шестнадцатеричном коде задаются в качестве аргументов командной строки для сценария. Я не использовал awk в скрипте, так как не знаком с ним. Я не смог прочитать несколько EDID из вывода xrandr --prop. Я полагаю, это может сделать awk. - person jarno; 03.04.2015
comment
Я познакомился с awk. Я опубликовал еще один ответ, посвященный этим и некоторым другим проблемам. Думаю, его код можно было бы использовать для вашего скрипта на GitHub. - person jarno; 07.04.2015
comment
Короткий сценарий не распечатывал самый последний вывод, который у меня был на моей машине; если бы я изменил output && hex, он бы снизился только до DP-6 и опустил DP-7. Изменение xrandr --prop на (xrandr --prop && echo) для добавления дополнительного разрыва строки исправило это. - person Ivan Vučica; 28.09.2020
comment
@IvanVučica: Хороший улов! Я исправил скрипт, echo больше не нужен. Спасибо, что указали на эту ошибку! - person MestreLion; 28.09.2020

Протестировано на Ubuntu 16.04, 18.04. (знаю, что поздно отвечать, но это решение актуально сегодня)

$ sudo apt-get install -y hwinfo
...
$ hwinfo --monitor --short
monitor:
                   SONY TV
                   AUO LCD Monitor

У меня подключено два монитора. Один с ноутбуком, а другой - внешний дисплей. Как только внешний монитор подключен или отключен, эта команда отражает изменение. Вам постоянно нужно проводить опрос. Удаление опции --short дает более подробную информацию.

Вы можете опросить состояние с помощью следующего фонового задания:

$ while true;
>  do
>   hwinfo --monitor --short;
>   sleep 2;
>  done >> monitor.log &

Цикл while true выполняется бесконечное количество раз. sleep 2 приостанавливает каждую итерацию цикла на 2 секунды. И вывод hwinfo --monitor --short добавляется к monitor.log. Этот файл журнала может предоставить вам историю активности подключаемого модуля монитора и подключаемого модуля.

К вашему сведению: я использую фоновый (демон) скрипт Python, используя приведенную выше команду (и другие подобные), чтобы определить, делает ли кто-то какие-либо подключаемые модули и подключаемые модули HW с системами в компьютерной лаборатории. Если это так, я получаю соответствующие уведомления о том, что кто-то подключил/отключил монитор, мышь или клавиатуру почти в режиме реального времени!

Подробнее о команде hwinfo можно узнать здесь. Его справочная страница также является хорошим источником.

person codeman48    schedule 11.05.2017
comment
Это самое простое и прямое - person Luis Lobo Borobia; 13.07.2021

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

Если вы хотите получить настоящее имя монитора, альтернативой решению @dtmilano является получение свойства EDID монитора с помощью libXrandr, а затем его ручной анализ и печать (прочитайте спецификацию EDID).

xrandrисходный код.

person pzanoni    schedule 09.05.2012
comment
Если вы пишете программу на C для этого, вы можете очень легко получить имя производителя монитора из идентификатора PNP (например, SAM => Samsung Electric Company): github.com/golightlyb/PNP-ID - person HoboBen; 26.11.2017

Я знаю, что это грязный способ, но он дает мне название модели монитора даже лучше, чем sudo get-edid|parse-edid. Он считывает информацию из массивов и выводит ее так, как если бы вы читали файл. Вы можете изменить его в соответствии с вашими потребностями.

#!/bin/bash
#
#
#    get-monitors.sh
#
#    Get monitor name and some other properties of connected monitors
#    by investigating the output of xrandr command and EDID data
#    provided by it.
#
#    Copyright (C) 2015,2016 Jarno Suni <[email protected]>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program. See <http://www.gnu.org/licenses/gpl.html>

set -o nounset
set -o errexit

# EDID format:
# http://en.wikipedia.org/wiki/Extended_Display_Identification_Data#EDID_1.3_data_format
# http://read.pudn.com/downloads110/ebook/456020/E-EDID%20Standard.pdf

declare -r us=';' # separator string;
# If EDID has more than one field with same tag, concatenate them,
# but add this string in between.

declare -r fs=$'\x1f' # Field separator for internal use;
# must be a character that does not occur in data fields.

declare -r invalid_edid_tag='--bad EDID--'
# If base EDID is invalid, don't try to extract information from it,
# but assign this string to the fields.

# Get information in these arrays:
declare -a outs  # Output names
declare -a conns # Connection type names (if available)
declare -a names # Monitor names (but empty for some laptop displays)
declare -a datas # Extra data; may include laptop display brand name
                 # and model name
declare -i no    # number of connected outputs (to be counted)

# xrandr command to use as a source of information:
declare -r xrandr_output_cmd="xrandr --prop"

hex_to_ascii() {
    echo -n "$1" | xxd -r -p
}

ascii_to_hex() {
    echo -n "$1" | xxd -p
}

get_info() {
    no=0
    declare OIFS=$IFS;
    IFS=$fs
    while read -r output conn hexn hexd; do
        outs[no]="${output}"
        conns[no]="${conn}"
        names[no]="$(hex_to_ascii "$hexn")"
        datas[no]="$(hex_to_ascii "$hexd")"
        (( ++no ))
    done < <(eval $xrandr_output_cmd | gawk -v gfs="$fs" '
        function print_fields() {
            print output, conn, hexn, hexd
            conn=""; hexn=""; hexd=""
        }
        function append_hex_field(src_hex,position,app_hex,  n) {
                     n=substr(src_hex,position+10,26)
                     sub(/0a.*/, "", n)
                     # EDID specification says field ends by 0x0a
                     # (\n), if it is shorter than 13 bytes.
                     #sub(/(20)+$/, "", n)
                     # strip whitespace at the end of ascii string
                     if (n && app_hex) return app_hex sp n
                      else return app_hex n
        }
        function get_hex_edid(  hex) {
            getline
            while (/^[ \t]*[[:xdigit:]]+$/) {
                sub(/[ \t]*/, "")
                hex = hex $0
                getline
            }
            return hex
        }
        function valid_edid(hex,  a, sum) {
            if (length(hex)<256) return 0
            for ( a=1; a<=256; a+=2 ) {
                # this requires gawk
                sum+=strtonum("0x" substr(hex,a,2))

                # this requires --non-decimal-data for gawk:
                #sum+=sprintf("%d", "0x" substr(hex,a,2))
            }
            if (sum % 256) return 0
            return 1
        }
        BEGIN {
            OFS=gfs
        }
        /[^[:blank:]]+ connected/ {
            if (unprinted) print_fields()
            unprinted=1
            output=$1
        }
        /[^[:blank:]]+ disconnected/ {
            if (unprinted) print_fields()
            unprinted=0
        }
        /^[[:blank:]]*EDID.*:/ {
            hex=get_hex_edid()
            if (valid_edid(hex)) {
                for ( c=109; c<=217; c+=36 ) {
                    switch (substr(hex,c,10)) {
                        case "000000fc00" :
                         hexn=append_hex_field(hex,c,hexn)
                         break
                        case "000000fe00" :
                         hexd=append_hex_field(hex,c,hexd)
                         break
                    }
                }
            } else {
              # set special value to denote invalid EDID
              hexn=iet; hexd=iet
            }
        }
        /ConnectorType:/ {
            conn=$2
        }
        END {
            if (unprinted) print_fields()
        }' sp=$(ascii_to_hex $us) iet=$(ascii_to_hex $invalid_edid_tag))

    IFS="$OIFS"
}

get_info

# print the colums of each display quoted in one row
for (( i=0; i<$no; i++ )); do
    echo "'${outs[i]}' '${conns[i]}' '${names[i]}' '${datas[i]}'"
done
person jarno    schedule 06.04.2015
comment
Отличный сценарий! Не знаю, каким должен быть четвертый параметр, на моих мониторах он остается пустым. Однако, если я изменяю 000000fe00 на 000000ff00, он показывает серийные номера моих мониторов. Это отлично подходит для определения того, какой монитор подключен к какому разъему. (000000fe00 согласно вики — это неуказанное текстовое поле.) - person Geeklab; 06.02.2018
comment
@Geeklab Спасибо. 000000fe00 — это смещение к неуказанному тексту по стандарту, но IIRC содержал кое-что значимое для какого-то старого монитора, который у меня был, поэтому я взял его. Эта версия использует GNU awk (gawk), который лучше подходит для этой задачи, но у меня есть сделал также более портативную версию этого. Я также добавил функциональность для получения размеров отображения в моей локальной копии. Может быть, я опубликую его, например. Гитхаб когда-нибудь. - person jarno; 22.05.2020
comment
@jarno: пожалуйста, пропингуйте меня, если да! - person MestreLion; 19.06.2020

Вы можете попробовать ddcprobe и/или get-edid

$ sudo apt-get install xresprobe read-edid
$ sudo ddcprobe
$ sudo get-edid
person Diego Torres Milano    schedule 08.05.2012
comment
Это не нужно. xrandr будет выводить имена окон из файла xorg.conf. Эти имена - то, что я ожидал. - person Jānis Gruzis; 08.05.2012
comment
Добавление parse-edid после get-edid делает вывод более содержательным. Мне это помогло sudo get-edid | parse-edid Если у вас несколько мониторов, вы можете отобразить подробности, используя sudo get-edid -b 0 | parse-edid --› для 1-го монитора. sudo get-edid -b 1 | parse-edid --› для второго монитора. - person Fear; 23.04.2018

Вы ищете информацию EDID, которая передается по шине I²C и интерпретируется вашим видеодрайвером. . Как говорит dtmilano, get-edit из ddcprobe должен работать.

Вы также можете получить эту информацию, зарегистрировав свой X start:

startx -- -logverbose 6

Несколько лет назад я использовал пакет под названием read-edid для сбора этой информации.

Пакет read-edid может быть уже доступен в Ubuntu, согласно этому сообщению в блоге с 2009 года.

person ghoti    schedule 09.05.2012