Linux retrieve monitor names
Asked Answered
C

7

30

Situation: I'm using multiple monitors and I want to get their names in bash. Currently I'm using Ubuntu 10.04.

I know about xrandr. From it I can get only statistics data. What I want is to read all monitor names in an array to work with them.

Is there a clear way to do that without cutting names from some kind of string? A clear way would be reading them from file. A not clear way would be to pipe xrandr output to some sort a function to cut names out from it.

Cogon answered 8/5, 2012 at 14:23 Comment(5)
As far as I know you need to get that from driver specific APIs. There used to be something in nvidia. What card do you have? Or did you need something generic?Coincident
@Coincident My video card is ATI Radeon HD 5000. Better of course would be to get more generic solution. But specific solution for my current machine also will do.Jauch
I agree that getting certain properties by parsing and decoding the output of xrandr --prop or xrandr --verbose is not a clear way, as the output formatting of xrandr is subject to change and is undocumented. I wish xrandr had ways to read individual properties of a given output (e.g. like exiftool has ways to read individual meta information tags of given files).Libb
I am not sure what kind of monitor names you want. Would it be enough to get the output names? I have noticed, that the EDID information of a laptop computer may not have a monitor name for the integrated display, but it may have some brand name and part name declared there anyway.Libb
There is similar topic in unix.stackexchange.com.Hydrolyze
M
11

sudo get-edid didn't work for me. (EDIT: now works on another computer, Lubuntu 14.10; I'd blame BIOS differences but that's a random guess...)

Anyway under X, xrandr --verbose prints the EDID block. Here is a quick and dirty way to extract it and pass to 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 = "";
}'
Mirella answered 15/8, 2013 at 2:39 Comment(3)
For Intel cards, edid files are provided in /sys. find /sys -name edid. This does not look to be the case for ATI. Can't verify for NVidia.Casillas
For the xrandr in Ubuntu 12.04, replace EDID: for EDID_DATA: in line 3. It works great when |strings is used, as per the in-code comment.Vesicle
I found out that xrandr knows current EDID better than the file found by the command @Casillas told, if you change monitor on fly.Libb
V
30

Inspired by Beni's answer, this will read the EDID data using xrandr and extract the monitors names according to the EDID specification, with no need of any external tools like 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
)

Uses awk to precisely extract the monitor name only, and no extra garbage from the EDID, hence "magic numbers" like 000000fc00, 26 and 0a. Finally uses xxd to convert from hex to ASCII, printing one monitor name per line.

Based on this solution I made a handy script to switch monitors, which can also be used to simply list monitor info:

$ 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
Vesicle answered 24/7, 2014 at 12:11 Comment(9)
I tested the inline script by my monitor and it prints nothing. I inspected the EDID and noticed that it has two Monitor Descriptors tagged as FCh, the first of which is L1715S and the second of which is empty. On my laptop there is no such descriptor for the integrated display, but two descriptors tagged as FEh, which apparently contain brand name CPT and model name CLAA102NA0A.Libb
At least one FCh entry is mandatory by the spec, so it's weird your laptop does not contain one... FEh stands for "unspecified text", basically a free text field, so I cannot rely on it containing relevant information. About printing nothing, open a question pasting both EDIDs so we can tweak the script for your case.Vesicle
Maybe the laptop display has no name since it is not a separate customer product.Libb
My other laptop has the same thing: Monitor brand name is in the first descriptor, and part name is in the second descriptor both tagged by FEh.Libb
A couple of real world sample EDIDs for testing: 00ffffffffffff001e6d6f432c340400110f01036e221b78ea2ee5a4574a9c25115054a56b80314f454f614f81800101010101010101302a009851002a4030701300520e1100001e000000fd00384b1e530e000a202020202020000000fc004c31373135530a202020202020000000fc000a2020202020202020202020200098, 00ffffffffffff00320c000000000000000f0102801e16780a74b09657548b282550540000000101010101010101010101010101010164190040410026301888360030e410000018000000000000000000000000000000000000000000fe004c475068696c6970734c43440a000000fe004c503135305830382d544c414100a3Libb
Actually, I have made a script that outputs the monitor name(s) field and the data field(s), when one or more hex coded EDIDs are given as command line arguments for the script. I didn't use awk in the script, since I am not familiar with it. I couldn't read multiple EDIDs from the output of xrandr --prop. I suppose it can be done by awk.Libb
I got familiar with awk. I posted another answer addressing these issues and some others. I think its code could be used for your script in GitHub.Libb
The short script didn't print out the very last output I had on my machine; if I changed output && hex, it would only go down to DP-6 and omit DP-7. Changing xrandr --prop to (xrandr --prop && echo) to add an extra line break fixed this.Gish
@IvanVučica: Nice catch! I've fixed the script, no need for echo anymore. Thanks for pointing out this bug!Vesicle
G
26

Tested on Ubuntu 16.04, 18.04. (I know its too late to answer but this solution is relevant today)

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

I have two monitors attached. One with the laptop and the other is an external display. As soon as the external monitor is plugged-in or out, this command reflects the change. You continuously need to poll. Removing the --short option gives more detailed information.

You can poll the state with the following background job:

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

The while true loop runs infinite times. The sleep 2 pauses each iteration of the loop for 2 seconds. And the output of hwinfo --monitor --short is appended to monitor.log. This log file can give you the activity history of monitor plug-in and plug-out.

FYI: I am using a background (daemon) python script using the above command (and other similar ones) to detect if someone is doing some HW plug-ins and plug-outs with the systems in the computer lab. If so, I get appropriate notifications that someone plugged-out/in a monitor, mouse or keyboard in almost real-time!

More info about hwinfo command is here. Its man page is also a good source.

Godin answered 11/5, 2017 at 16:17 Comment(2)
This is the simplest and straight to the pointOligocene
Using this solution, the command hwinfo --monitor --short returns no results. Why?Schapira
M
11

sudo get-edid didn't work for me. (EDIT: now works on another computer, Lubuntu 14.10; I'd blame BIOS differences but that's a random guess...)

Anyway under X, xrandr --verbose prints the EDID block. Here is a quick and dirty way to extract it and pass to 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 = "";
}'
Mirella answered 15/8, 2013 at 2:39 Comment(3)
For Intel cards, edid files are provided in /sys. find /sys -name edid. This does not look to be the case for ATI. Can't verify for NVidia.Casillas
For the xrandr in Ubuntu 12.04, replace EDID: for EDID_DATA: in line 3. It works great when |strings is used, as per the in-code comment.Vesicle
I found out that xrandr knows current EDID better than the file found by the command @Casillas told, if you change monitor on fly.Libb
V
2

You may try ddcprobe and/or get-edid

$ sudo apt-get install xresprobe read-edid
$ sudo ddcprobe
$ sudo get-edid
Veolaver answered 8/5, 2012 at 18:15 Comment(2)
This didnt output needed. xrandr would output window names from xorg.conf file. Those names are what I expected.Jauch
Adding parse-edid after get-edid makes the output more meaningful.This worked for me sudo get-edid | parse-edid If you have multiple monitors you can display details using sudo get-edid -b 0 | parse-edid --> for 1st monitor. sudo get-edid -b 1 | parse-edid --> for 2nd monitor.Greenes
P
2

If you don't want to parse xrandr output, write a C program using libXrandr that gets only what you want. If all you want to do is to query information, it can be done quickly. Read this document.

If you want to get the real monitor name, an alternative to @dtmilano's solution is to get the EDID property of the monitor using libXrandr and then manually parse it and print (read the EDID specification).

xrandr source code.

Peafowl answered 9/5, 2012 at 12:29 Comment(1)
If you're writing a C program to do this, you can get the monitor vendor name from the PNP ID (e.g. "SAM" => "Samsung Electric Company") really easily using this: github.com/golightlyb/PNP-IDLinares
L
2

I know this is a dirty way, but it gives me some monitor model name even better than sudo get-edid|parse-edid. It reads information in arrays, and outputs it in a way that can be read like you would read a file. You may modify it according to your needs.

#!/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
Libb answered 6/4, 2015 at 23:20 Comment(4)
Great script! Not sure though what the fourth parameter should be, it stays empty with my monitors. However, if I change 000000fe00 to 000000ff00, it shows my monitors serial numbers. This is great for detecting which monitor is hooked up to what connector. (000000fe00 according to wiki is an unspecified text field.)Plural
@Plural Thanks. 000000fe00 is the offset to unspecified text according to the standard, but IIRC it contained something meaningful information of some old monitor I had, so I took it in. This version uses GNU awk (gawk) which suits better for this task, but I have made also some more portable version of this. I also added functionality to get display dimensions in my local copy. Maybe I will publish it in e.g. GitHub someday.Libb
@jarno: please ping me if you do!Vesicle
@Plural in my system the "000000ff00" field is empty for all monitors. In EDID 1.4. there is also serial number at bytes 12-15 of the raw data, but it is not the same I suppose.Libb
S
0

You're looking for EDID information, which is passed along an I²C bus and interpreted by your video driver. As dtmilano says, get-edit from ddcprobe should work.

You can also get this information by logging your X start:

startx -- -logverbose 6

Years ago, I used a package called read-edid to gather this information.

The read-edid package may be available in Ubuntu already, according to this blog post from 2009.

Selfseeker answered 9/5, 2012 at 12:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.