Команда разбора Bash в 2d массив - PullRequest
0 голосов
/ 12 июня 2019

Я хочу создать скрипт, который перечисляет все доступные устройства 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) и отслеживать его активность.

Я попытался прочитать вывод командыслово за словом, но это кажется бесполезным, поскольку количество слов в каждом поле варьируется от 1 до 5 или даже больше.Можно ли проанализировать ввод этой команды в 2d массив, где одно измерение будет хранить устройство?Например, в идеале я бы имел

mDevicesArray[0] = { "0:0", "System, "Timer"} 
mDevicesArray[1] = { "0:1", "System", "Announce"}
...
mDevicesArray[4] = { "28:0", "Launchpad S", "Launchpad S MIDI 1"}

и затем использовал бы этот массив для дальнейшей обработки устройств.

Ответы [ 2 ]

2 голосов
/ 13 июня 2019

Bash не имеет 2D-массивов. Вы можете смоделировать один с ассоциативным массивом, если скорость выполнения не имеет большого значения:

$ cat ./tst.sh
#!/bin/env bash

declare -A mDevicesArray

mDevicesSet() {
    local rowNr="$1" 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, например ::10000

$ cat tst.sh
#!/bin/bash

mDevicesSet() {
    local rowNr="$1"
    shift
    mDevicesArray1["$rowNr"]="$1"
    mDevicesArray2["$rowNr"]="$2"
    mDevicesArray3["$rowNr"]="$3"
}

mDevicesGet() {
    local rowNr=$1 colNr=$2 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

По сравнению с использованием ассоциативных массивов, хотя и выполняется быстрее, недостатки подхода индексированных массивов заключаются в том, что у вас есть жестко запрограммированное количество столбцов (3), и каждая строка должна иметь одинаковое количество столбцов, и сложнее расширять по более чем 2 показателям.

1 голос
/ 13 июня 2019

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.)

...