我有一个工作 shell 脚本,可以在插入外部 USB 键盘时为其分配不同的布局,但它不再工作。我不知道这是因为我从sh切换到zsh。
usbkbd_id="$(xinput -list | grep "USB Keyboard" | awk -F'=' '{print $2}' | grep "keyboard" | cut -c 1-2)"
for ID in $usbkbd_id; do
setxkbmap -device ${ID} -layout "es"
done
我注意到,当我用命令检查它时,echo "device: ${ID} layout: ${usbkbd_layout}" >> test.txt
它实际上并没有循环遍历每个 ID,而是简单地在整个第一个变量输出的开头添加“device:”...
我已经经历了类似的问题和答案,尝试了我见过的不同替代方案,例如${usbkbd_id[@]}
,用我的初学者水平脚本编写技能,但我无法解决这个问题。
实际上,也许真正的问题根源在于我总是为我的外部 USB 键盘获取 3 个 ID,而实际上将键盘布局仅分配给其中一个是有效的,但我无法确定是哪一个。所以有时这个命令有效,有时则无效(当正确的 ID 不是我猜的最后一个时)。
答案1
var=value
是一个标量赋值。它分配一并且只有一个值$var
.您可能sh
对它也是标量赋值的行为感到困惑,但自从sh
,但由于没有列表/数组变量,因此变量的扩展在未引用时会经历特殊的 split+glob 操作(原因是总体而言存在许多错误和安全问题并固定在大多数更现代的 shell 中,包括rc
、es
、fish
或zsh
)。
在这里,由于您想要存储多个值,因此您想要使用数组/列表变量,而不是标量变量。
在 中zsh
,数组变量赋值是通过以下方式完成的:
var=( values )
句法。
所以:
usbkbd_ids=(
$(xinput list | grep -Po 'USB Keyboard.*id=\K\d+(?=.*keyboard)')
)
for id in $usbkbd_ids; do
setxkbmap -device $id -layout es
done
虽然在这里,你不妨这样做:
xinput list |
grep -Po 'USB Keyboard.*id=\K\d+(?=.*keyboard)' |
xargs -I ID setxkbmap -device ID -layout es
请注意,您很少需要将awk
,grep
和cut
一起使用,它awk
是其他两个命令的超集。然而,awk
它不太擅长基于模式的提取(除非您可以使用 GNUawk
扩展)。上面-P
是一个非标准grep
扩展。作为标准替代方案,您可以使用sed
:
xinput list |
sed -n 's/^.*USB Keyboard.*id=\([0-9]*\).*keyboard.*/\1/p'
对于标准awk
,这可能是:
xinput list |
awk '/USB Keyboard.*id=.*keyboard/ && match($0, /id=[0-9]+/) {
print substr($0, RSTART + 3, RLENGTH - 3)
}'
您还可以使用zsh
自己的模式提取功能,例如:
usbkbd_ids=()
for line (${(f)"$(xinput list)"})
[[ $line =~ 'USB Keyboard.*id=([0-9]+).*keyboard' ]] &&
usbkbd_ids+=$match[1]