Разбор результата команды в скрипте bash для Linux
Я пишу небольшой сценарий bash в Linux для управления входами / выходами Pulseaudio.
Я хочу направить все входы приемников, кроме одного, в тот или иной приемник. Вход-сток, который я не хочу направлять, это:
pi@raspberrypi:~/fonction $ pactl list sink-inputs
Sink Input #36062
Driver: protocol-native.c
Owner Module: 2
Client: 198
Sink: 2
Sample Specification: s16le 2ch 44100Hz
Channel Map: front-left,front-right
Format: pcm, format.sample_format = "\"s16le\"" format.rate = "44100" format.channels = "2" format.channel_map = "\"front-left,front-right\""
Corked: no
Mute: no
Volume: front-left: 65536 / 100% / 0.00 dB, front-right: 65536 / 100% / 0.00 dB
balance 0.00
Buffer Latency: 120000 usec
Sink Latency: 236349 usec
Resample method: n/a
Properties:
media.name = "ALSA Playback"
application.name = "ALSA plug-in [snapclient]"
native-protocol.peer = "UNIX socket client"
native-protocol.version = "32"
application.process.id = "539"
application.process.user = "snapclient"
application.process.host = "raspberrypi"
application.process.binary = "snapclient"
application.language = "C"
application.process.machine_id = "69e523231bb44f2e926a758a63cbb5b1"
module-stream-restore.id = "sink-input-by-application-name:ALSA plug-in [snapclient]"
Чтобы переместить вход приемника в другой приемник, мне нужно использовать эту команду:
pactl move-sink-input <sink-input id> <sink id>
Поэтому я должен разобрать результат первой команды, чтобы получить Sink Input #ID
(содержится в первой строке), но я должен использовать условие, чтобы проверить, module-stream-restore.id
(последняя строка) действительно то, что я хочу направить.
Мне нужно что-то вроде:
if [ <last line> = 'sink-input name I need' ]
then
pactl move-sink-input <id from first line> <my sink name>
fi
Я просто не знаю, как разобрать команду, чтобы получить ОБА информацию.
Прямо сейчас я могу получить только последнюю строку или только #ID.
pactl list short sink-inputs|while read stream; do
streamId=$(echo $stream )
id=$(echo pactl list sink-inputs | grep module-stream-restore.id | grep -o '".*"' |sed 's/"//g')
if [ "$streamId" != 'sink-input-by-application-name:ALSA plug-in [snapclient]' ]
then
pactl move-sink-input "$streamId" Snapcast
fi
Как мне приступить к анализу результата pactl list sink-inputs
так что я могу прочитать два элемента, а не только один, в каждом "блоке" (иначе говоря, каждый вход-приемник) результата этой команды в скрипте bash?
2 ответа
Концепт:
- взывать
pactl …
сLC_ALL=C
установите, чтобы избежать локализованного вывода (вам, видимо, это не нужно, но в общем случае люди это делают). использование
egrep
отказаться от неактуальных линий. Вы хотите получить пары строк, которые выглядят так:Sink Input #12345 module-stream-restore.id = "whatever"
Предполагая, что линии идут парами,
read
их два на два с надлежащимIFS
(#
для первой строки в паре,=
для второго) извлечь соответствующие данные. Используйте фиктивные переменные для деталей, которые вам не нужны.- Работа с извлеченными данными. Обратите внимание, что
IFS='='
для второй строки в паре будет извлекать все после=
т.е. соседнее пространство и двойные кавычки. Вот почему в коде (ниже) я сопоставляю' "sink-… [snapclient]"'
, не просто'sink-… [snapclient]'
,
Код:
LC_ALL=C pactl list sink-inputs |
egrep "^Sink Input #|module-stream-restore.id = " |
while IFS='#' read dummy id && IFS='=' read dummy restid; do
if [ "$restid" = ' "sink-input-by-application-name:ALSA plug-in [snapclient]"' ] ; then
printf 'Match for ID %s.\n' "$id"
# do something
else
printf 'No match for ID %s.\n' "$id"
# do something else
fi
done
Проблема в том, что переменные, установленные в do
Цикл не поддерживается от одного прохода к следующему.
Простое решение - сохранить вывод списка во временный файл, а затем дважды отсканировать его:
pactl list short sink-inputs >temp.lst
streamId=$(sed -n 's/^Sink Input #\(.*\)$/\1/p' <temp.lst)
id=$(sed -n 's/.*module-stream-restore.id = "\(.*\)"$/\1/p' <temp.lst)
rm temp.lst
Теперь у вас есть две переменные, которые вам нужны. Это не очень элегантное решение, но оно простое и легкое для понимания и обслуживания. Обратите внимание, что я использовал sed
выполнить grep
Функции: руководство по тому, как это работает, смотрите здесь.
Тем не менее, вы можете избежать временного файла с более запутанным решением:-
Ids="$(pactl list short sink-inputs | \
sed -n -e 's/^Sink Input #\(.*\)$/\1/p' \
-e 's/.*module-stream-restore.id = "\(.*\)"$/\1/p')"
Теперь у вас есть обе переменные в Ids
, разделенные новой строкой: вы можете разделить их с помощью:-
streamId="${Ids%$'\n'*}"
Id="${Ids#*$'\n'}"
Если вам не нравятся временные переменные, вы можете использовать Id
вместо Ids
!
Я проверил это, скопировав вывод списка и используя его вместо реального pactl
команда, так что все должно работать с живой командой.