Я пишу небольшой 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?
решение1
Проблема в том, что переменные, заданные в 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
команды, так что все должно работать с реальной командой.
решение2
Концепт:
- Вызовите
pactl …
с помощьюLC_ALL=C
set, чтобы избежать локализованного вывода (вам это, по-видимому, не нужно, но в общем случае людям нужно). Используйте
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