Estou escrevendo um pequeno script bash no Linux para controlar entradas/saídas do Pulseaudio.
O que eu quero fazer é rotear todas as entradas do coletor, exceto uma, para um ou outro coletor. A entrada do coletor que não quero rotear é esta:
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]"
Para mover uma entrada de coletor para outro coletor, preciso usar este comando:
pactl move-sink-input <sink-input id> <sink id>
Portanto, tenho que analisar o resultado do primeiro comando para obter o Sink Input #ID
(contido na primeira linha), mas tenho que usar uma condição para verificar se module-stream-restore.id
(última linha) é realmente o que desejo rotear.
Eu precisaria de algo como:
if [ <last line> = 'sink-input name I need' ]
then
pactl move-sink-input <id from first line> <my sink name>
fi
Só não sei como analisar o comando para obter AMBAS as informações.
No momento, consigo obter apenas a última linha ou apenas o #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
Como procedo para analisar o resultado pactl list sink-inputs
para poder ler dois elementos, não apenas um, em cada "bloco" (também conhecido como entrada de coletor) do resultado desse comando em um script bash?
Responder1
O problema é que as variáveis definidas no do
loop não são mantidas de uma passagem para a próxima.
A solução simples é salvar a saída da lista em um arquivo temporário e depois digitalizá-la duas vezes: –
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
Agora você tem as duas variáveis que precisa definir. Não é uma solução muito elegante, mas é simples e fácil de entender e manter. Observe que eu costumava sed
executar as grep
funções: para obter um guia de como isso funciona, consulteaqui.
No entanto, você pode evitar o arquivo temporário com uma solução mais complicada: –
Ids="$(pactl list short sink-inputs | \
sed -n -e 's/^Sink Input #\(.*\)$/\1/p' \
-e 's/.*module-stream-restore.id = "\(.*\)"$/\1/p')"
Agora você tem ambas as variáveis Ids
separadas por uma nova linha: você pode dividi-las com: -
streamId="${Ids%$'\n'*}"
Id="${Ids#*$'\n'}"
Se você também não gosta de variáveis temporárias, pode usar Id
em vez de Ids
!
Eu testei isso copiando a saída da sua lista e usando isso em vez de um pactl
comando real, então tudo deve funcionar com um comando ativo.
Responder2
O conceito:
- Invoque
pactl …
comLC_ALL=C
set para evitar saída localizada (aparentemente você não precisa disso, mas em geral as pessoas precisam). Use
egrep
para descartar linhas irrelevantes. Você deseja obter pares de linhas assim:Sink Input #12345 module-stream-restore.id = "whatever"
Supondo que as linhas vão aos pares,
read
faça-as duas a duas com o devidoIFS
(#
para a primeira linha do par,=
para a segunda) para extrair dados relevantes. Use variáveis fictícias para peças desnecessárias.- Trabalhe com dados extraídos. Observe que
IFS='='
para a segunda linha de um par extrairá tudo após o=
, ou seja, o espaço adjacente e as aspas duplas também. É por isso que no código (abaixo) eu comparo contra' "sink-… [snapclient]"'
, não apenas'sink-… [snapclient]'
.
O código:
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