Bash 将命令解析为二维数组
Bash parse command into 2d array
我想制作一个脚本,列出所有可用的 MIDI 设备并提示用户选择一个,然后为每个音符分配快捷方式。
我设法使用 aseqdump -l
获得了所有设备的列表。在我的例子中,输出:
Port Client name Port name
0:0 System Timer
0:1 System Announce
14:0 Midi Through Midi Through Port-0
20:0 UMC404HD 192k UMC404HD 192k MIDI 1
28:0 Launchpad S Launchpad S MIDI 1
用我最少的技能,我制作了一个脚本,在每一行之前添加了一个数字,所以它看起来像这样:
Port Client name Port name
1) 0:0 System Timer
2) 0:1 System Announce
3) 14:0 Midi Through Midi Through Port-0
4) 20:0 UMC404HD 192k UMC404HD 192k MIDI 1
5) 28:0 Launchpad S Launchpad S MIDI 1
然后提示用户根据左边的数字选择设备。所有的乐趣和游戏,但我不知道如何只读取设备名称。例如,如果用户输入“4”,我希望我的 mDevice 变量等于 "UMC404HD 192k",这样我就可以调用 aseqdump -p $(mDevice)
并监视它的 activity.
我尝试逐字阅读命令输出,但这似乎毫无用处,因为每个字段中的字数从 1 到 5 甚至更多不等。是否可以将此命令的输入解析为二维数组,其中一维将存储设备?例如,理想情况下我会
mDevicesArray[0] = { "0:0", "System, "Timer"}
mDevicesArray[1] = { "0:1", "System", "Announce"}
...
mDevicesArray[4] = { "28:0", "Launchpad S", "Launchpad S MIDI 1"}
然后使用这个数组进一步处理设备。
bash 没有二维数组。只要执行速度不是什么大问题,您就可以使用关联数组来模拟一个:
$ cat ./tst.sh
#!/bin/env bash
declare -A mDevicesArray
mDevicesSet() {
local rowNr="" colNr
shift
for (( colNr=1; colNr<=$#; colNr++ )); do
mDevicesArray["${rowNr},${colNr}"]="${!colNr}"
done
}
mDevicesSet 1 '0:0' 'System' 'Timer'
mDevicesSet 2 '0:1' 'System' 'Announce'
mDevicesSet 3 '14:0' 'Midi Through' 'Midi Through Port-0'
mDevicesSet 4 '20:0' 'UMC404HD 192k' 'UMC404HD 192k MIDI 1'
mDevicesSet 5 '28:0' 'Launchpad S' 'Launchpad S MIDI 1'
printf '%s\n' "${mDevicesArray[4,2]}"
$ ./tst.sh
UMC404HD 192k
否则还有其他各种解决方法,例如使用 eval
我不推荐,或者为了简单、健壮和高效,您可以只使用 mDevicesArray1[1]="0:0"; mDevicesArray2[1]="System"; mDevicesArray3[1]="Timer"
等等,然后简单地编写函数来访问数组,就好像它们是 2D 一样,例如:
$ cat tst.sh
#!/bin/bash
mDevicesSet() {
local rowNr=""
shift
mDevicesArray1["$rowNr"]=""
mDevicesArray2["$rowNr"]=""
mDevicesArray3["$rowNr"]=""
}
mDevicesGet() {
local rowNr= colNr= val
case $colNr in
1 ) val="${mDevicesArray1[$rowNr]}" ;;
2 ) val="${mDevicesArray2[$rowNr]}" ;;
3 ) val="${mDevicesArray3[$rowNr]}" ;;
esac
printf '%s\n' "$val"
}
mDevicesSet 1 '0:0' 'System' 'Timer'
mDevicesSet 2 '0:1' 'System' 'Announce'
mDevicesSet 3 '14:0' 'Midi Through' 'Midi Through Port-0'
mDevicesSet 4 '20:0' 'UMC404HD 192k' 'UMC404HD 192k MIDI 1'
mDevicesSet 5 '28:0' 'Launchpad S' 'Launchpad S MIDI 1'
printf '%s\n' "$(mDevicesGet 4 2)"
$ ./tst.sh
UMC404HD 192k
与使用关联数组相比,虽然执行速度更快,但索引数组方法的缺点是您有 hard-coded 列数 (3),并且每行必须具有相同的列数和很难扩展到 2 个以上的索引。
aseqdump
仅列出输入端口,列输出使其难以解析。
解析 aconnect
的输出会更容易,它每行只有一个客户端或端口,并使用分隔符:
$ aconnect -io
client 0: 'System' [type=kernel]
0 'Timer '
1 'Announce '
client 64: 'Rawmidi 0 - EMU10K1 MPU-401 (UART)' [type=kernel]
0 'EMU10K1 MPU-401 (UART)'
client 65: 'Emu10k1 WaveTable' [type=kernel]
0 'Emu10k1 Port 0 '
1 'Emu10k1 Port 1 '
2 'Emu10k1 Port 2 '
3 'Emu10k1 Port 3 '
client 128: 'DMIDI' [type=user]
0 'DMIDI - Receive: [ff:ff:ff:ff]'
1 'DMIDI - Transmit [ff:ff:ff:ff]'
client 129: 'LinuxSampler' [type=user]
0 'LinuxSampler '
(如果您实际上只需要输入端口,请仅使用 -i
。)
我想制作一个脚本,列出所有可用的 MIDI 设备并提示用户选择一个,然后为每个音符分配快捷方式。
我设法使用 aseqdump -l
获得了所有设备的列表。在我的例子中,输出:
Port Client name Port name
0:0 System Timer
0:1 System Announce
14:0 Midi Through Midi Through Port-0
20:0 UMC404HD 192k UMC404HD 192k MIDI 1
28:0 Launchpad S Launchpad S MIDI 1
用我最少的技能,我制作了一个脚本,在每一行之前添加了一个数字,所以它看起来像这样:
Port Client name Port name
1) 0:0 System Timer
2) 0:1 System Announce
3) 14:0 Midi Through Midi Through Port-0
4) 20:0 UMC404HD 192k UMC404HD 192k MIDI 1
5) 28:0 Launchpad S Launchpad S MIDI 1
然后提示用户根据左边的数字选择设备。所有的乐趣和游戏,但我不知道如何只读取设备名称。例如,如果用户输入“4”,我希望我的 mDevice 变量等于 "UMC404HD 192k",这样我就可以调用 aseqdump -p $(mDevice)
并监视它的 activity.
我尝试逐字阅读命令输出,但这似乎毫无用处,因为每个字段中的字数从 1 到 5 甚至更多不等。是否可以将此命令的输入解析为二维数组,其中一维将存储设备?例如,理想情况下我会
mDevicesArray[0] = { "0:0", "System, "Timer"}
mDevicesArray[1] = { "0:1", "System", "Announce"}
...
mDevicesArray[4] = { "28:0", "Launchpad S", "Launchpad S MIDI 1"}
然后使用这个数组进一步处理设备。
bash 没有二维数组。只要执行速度不是什么大问题,您就可以使用关联数组来模拟一个:
$ cat ./tst.sh
#!/bin/env bash
declare -A mDevicesArray
mDevicesSet() {
local rowNr="" colNr
shift
for (( colNr=1; colNr<=$#; colNr++ )); do
mDevicesArray["${rowNr},${colNr}"]="${!colNr}"
done
}
mDevicesSet 1 '0:0' 'System' 'Timer'
mDevicesSet 2 '0:1' 'System' 'Announce'
mDevicesSet 3 '14:0' 'Midi Through' 'Midi Through Port-0'
mDevicesSet 4 '20:0' 'UMC404HD 192k' 'UMC404HD 192k MIDI 1'
mDevicesSet 5 '28:0' 'Launchpad S' 'Launchpad S MIDI 1'
printf '%s\n' "${mDevicesArray[4,2]}"
$ ./tst.sh
UMC404HD 192k
否则还有其他各种解决方法,例如使用 eval
我不推荐,或者为了简单、健壮和高效,您可以只使用 mDevicesArray1[1]="0:0"; mDevicesArray2[1]="System"; mDevicesArray3[1]="Timer"
等等,然后简单地编写函数来访问数组,就好像它们是 2D 一样,例如:
$ cat tst.sh
#!/bin/bash
mDevicesSet() {
local rowNr=""
shift
mDevicesArray1["$rowNr"]=""
mDevicesArray2["$rowNr"]=""
mDevicesArray3["$rowNr"]=""
}
mDevicesGet() {
local rowNr= colNr= val
case $colNr in
1 ) val="${mDevicesArray1[$rowNr]}" ;;
2 ) val="${mDevicesArray2[$rowNr]}" ;;
3 ) val="${mDevicesArray3[$rowNr]}" ;;
esac
printf '%s\n' "$val"
}
mDevicesSet 1 '0:0' 'System' 'Timer'
mDevicesSet 2 '0:1' 'System' 'Announce'
mDevicesSet 3 '14:0' 'Midi Through' 'Midi Through Port-0'
mDevicesSet 4 '20:0' 'UMC404HD 192k' 'UMC404HD 192k MIDI 1'
mDevicesSet 5 '28:0' 'Launchpad S' 'Launchpad S MIDI 1'
printf '%s\n' "$(mDevicesGet 4 2)"
$ ./tst.sh
UMC404HD 192k
与使用关联数组相比,虽然执行速度更快,但索引数组方法的缺点是您有 hard-coded 列数 (3),并且每行必须具有相同的列数和很难扩展到 2 个以上的索引。
aseqdump
仅列出输入端口,列输出使其难以解析。
解析 aconnect
的输出会更容易,它每行只有一个客户端或端口,并使用分隔符:
$ aconnect -io
client 0: 'System' [type=kernel]
0 'Timer '
1 'Announce '
client 64: 'Rawmidi 0 - EMU10K1 MPU-401 (UART)' [type=kernel]
0 'EMU10K1 MPU-401 (UART)'
client 65: 'Emu10k1 WaveTable' [type=kernel]
0 'Emu10k1 Port 0 '
1 'Emu10k1 Port 1 '
2 'Emu10k1 Port 2 '
3 'Emu10k1 Port 3 '
client 128: 'DMIDI' [type=user]
0 'DMIDI - Receive: [ff:ff:ff:ff]'
1 'DMIDI - Transmit [ff:ff:ff:ff]'
client 129: 'LinuxSampler' [type=user]
0 'LinuxSampler '
(如果您实际上只需要输入端口,请仅使用 -i
。)