首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过xRandR在Linux上配置监视器的BASH脚本

通过xRandR在Linux上配置监视器的BASH脚本
EN

Code Review用户
提问于 2018-11-26 18:40:58
回答 1查看 294关注 0票数 3

我的主计算机是一台笔记本电脑,我在Arch上运行i3wm。因此,我的监视器情况有时会发生变化,所以我想编写一个脚本,根据监视器连接到系统的情况来配置我的监视器。脚本在i3wm启动时运行。

至于显示器,有时我可能没有连接外部显示器,有时可能连接HDMI和DP显示器,有时我可能在另一个位置连接HDMI和DP显示器,但DP显示为不同的输出。

监测器如下:

  • eDP-1 -内部显示。
  • HDMI-2 -我的二次显示器之一,具有相同的分辨率和位置
  • DP-1DP-1-8 -我的主要显示器之一,它们是相同的监视器和位置,但显示为不同的输出。

守则如下:

代码语言:javascript
复制
#!/usr/bin/env bash

# The xRandR names of my monitors, including the internal laptop monitor / display
readonly MON_INTERNAL='eDP-1'
readonly MON1='DP-1'
readonly MON1_FALLBACK='DP-1-8'
readonly MON2='HDMI-2'

# The resolutiond of the given xRandR monitors / displays. NOTE: $MON1 and $MON1_FALLBACK are the same display, so only one res is needed
readonly MON_INTERNAL_RES='1920x1080'
readonly MON1_RES='2560x1440'
readonly MON2_RES='1680x1050'

main_mon=''
sec_mon=''

# Store a count of how many monitors are connected
mon_count=$(xrandr -q | grep -w 'connected' | wc -l)

# Configure the monitors via xRandR
config_monitors() {
    if [[ "$#" -eq "2" ]]; then
        xrandr --output $1 --primary --mode $2 --rotate normal --pos 0x0
    elif [[ "$#" -eq "4" ]]; then
        xrandr --output $MON_INTERNAL --off --output $1 --mode $2 --pos 1680x0 --right-of $3 --output $3 --mode $4 --pos 0x0 --left-of $1
    fi
}

# Determine which main monitor is available
if [[ $mon_count -gt 1 ]]; then
    # The name of which main monitor is connected (either $MON1 or $MON1_FALLBACK)
    main_mon=$(xrandr -q | grep -w 'connected'| grep "^$MON1\|^$MON1_FALLBACK" | awk '{ print $1 }')
else # fallback to laptop display $MON_INTERNAL because the hardcoded displays aren't connected
    main_mon=$MON_INTERNAL
fi

# Determine whether the secondary HDMI monitor, $MON2 is connected
if [[ $mon_count -gt 1 ]] && [[ $(xrandr -q | grep $MON2 | awk '{ print $2 }') -eq connected ]]; then
    sec_mon=$MON2
fi

# Configure both external monitors if they're set or use the internal display
# TODO: Actual fallback logic for when HDMI display is connected but not the primary DP-x..
if [[ -n $main_mon ]] && [[ -n $sec_mon ]]; then
    config_monitors "$main_mon" "$MON1_RES" "$sec_mon" "$MON2_RES"
else
    config_monitors "$MON_INTERNAL" "$MON_INTERNAL_RES"
fi

任何关于如何改进这个脚本的功能和/或可读性的建议都会受到极大的赞赏。这是我第一次真正地尝试编写一个实际服务于我的实际用途的Bash脚本。

EN

回答 1

Code Review用户

回答已采纳

发布于 2018-12-25 12:06:57

对于这样的问题,它有助于分解可能的状态,并为每个状态映射您想要做的事情,然后构建一个数据模型,使复制最小化。

以下是我对你问题的处理方法:

  1. 按偏好顺序硬编码的监视器数组,允许通配符
  2. 硬编码的assoc每个首选项的屏幕分辨率数组
  3. 硬编码的assoc每个可能配置的选项模板数组
  4. 从(1)和xrandr输出构造实际可用监视器名称的数组。
  5. 从(2)和(4)构造分辨率数组
  6. 从(3)和(4)获取选项模板
  7. 使用(4)和(5)填充模板

__

代码语言:javascript
复制
#!/usr/bin/env bash

# each PRIORITY entry must have matching entry in MODE; $displays will be sorted in priority order
declare -ar PRIORITY=( "DP-1*" HDMI-2 eDP-1 )
declare -Ar MODE=(
        [eDP-1]=1920x1080
        [DP-1*]=2560x1440
        [HDMI-2]=1680x1050
    )

# options corresponding to each possible config.  sorted in PRIORITY order.  
# left hand side is matched against space-separated list of actual monitor labels from xrandr
# template values like  are zero-based
declare -Ar OPTS=(
            [DP-1* HDMI-2 eDP-1]='--output  --off --output  --mode  --pos 1680x0 --right-of  --output  --mode  --pos 0x0 --left-of '
            [HDMI-2 eDP-1]='--output  --off --output  --mode  --pos 0x0'
            [eDP-1*]='--output  --primary --mode  --rotate normal --pos 0x0'
        )

declare -ar ALL_CONNECTED=( $( { xrandr -q || exit 1; } | awk '$2 == "connected" {print $1}' ) )


[[ ${#ALL_CONNECTED[@]} = 0 ]] && {
    echo no monitors connected
    exit 1
}

declare -a displays=()
declare -a modes=()

# populate displays and modes in preference order from ALL_CONNECTED 
for (( i=0; i<${#PRIORITY[@]}; i++ )); do
    for (( j=0; j<${#ALL_CONNECTED[@]}; j++ )); do
        if [[ ${ALL_CONNECTED[$j]} == ${PRIORITY[$i]} ]]; then
            displays+=( ${ALL_CONNECTED[$j]} )
            modes+=( ${MODE[${PRIORITY[$i]}]} )
            break
        fi
    done
done

echo "
ALL_CONNECTED: ${ALL_CONNECTED[@]}
displays: ${displays[@]}
modes: ${modes[@]}
"

for i in "${!OPTS[@]}"; do
    if [[ "${displays[@]}" == $i ]]; then
        opts=${OPTS[$i]}
        opts=${opts///\]\}}
        set -x
        xrandr $( eval echo $opts )
        exit $?
    fi
done
echo "no OPT setting found for connected display combination of ${ALL_CONNECTED[@]} [ ${displays[@]} ]"
exit 1
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/208466

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档