Estoy escribiendo un pequeño script bash en Linux para controlar las entradas/salidas de Pulseaudio.
Lo que quiero hacer es enrutar todas las entradas de fregadero, excepto una, a uno u otro fregadero. La entrada receptora que no quiero enrutar es 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 una entrada de receptor a otro receptor, necesito usar este comando:
pactl move-sink-input <sink-input id> <sink id>
Entonces tengo que analizar el resultado del primer comando para obtener Sink Input #ID
(contenido en la primera línea) pero tengo que usar una condición para verificar si module-stream-restore.id
(última línea) es realmente lo que quiero enrutar.
Necesitaría algo como:
if [ <last line> = 'sink-input name I need' ]
then
pactl move-sink-input <id from first line> <my sink name>
fi
Simplemente no sé cómo analizar el comando para obtener AMBAS informaciones.
En este momento, solo puedo obtener la última línea o solo el #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
¿Cómo procedo a analizar el resultado pactl list sink-inputs
para poder leer dos elementos, no solo uno, en cada "bloque" (también conocido como cada entrada receptor) del resultado de ese comando en un script bash?
Respuesta1
El problema es que las variables establecidas en el do
bucle no se mantienen de una pasada a la siguiente.
La solución simple es guardar el resultado de la lista en un archivo temporal y luego escanearlo dos veces: -
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
Ahora tiene las dos variables que necesita configurar. No es una solución muy elegante, pero es sencilla y fácil de entender y mantener. Tenga en cuenta que lo he utilizado sed
para realizar las grep
funciones: para obtener una guía sobre cómo funciona esto, consulteaquí.
Sin embargo, puede evitar el archivo temporal con una solución más complicada: –
Ids="$(pactl list short sink-inputs | \
sed -n -e 's/^Sink Input #\(.*\)$/\1/p' \
-e 's/.*module-stream-restore.id = "\(.*\)"$/\1/p')"
Ahora tienes ambas variables en Ids
, separadas por una nueva línea: puedes dividirlas con:-
streamId="${Ids%$'\n'*}"
Id="${Ids#*$'\n'}"
Si tampoco te gustan las variables temporales, puedes usar Id
en lugar de Ids
!
Probé esto copiando el resultado de su lista y usándolo en lugar de un pactl
comando real, por lo que todo debería funcionar con un comando en vivo.
Respuesta2
El concepto:
- Invoque
pactl …
conLC_ALL=C
set para evitar la salida localizada (aparentemente no necesita esto, pero en general la gente sí lo necesita). Úselo
egrep
para descartar líneas irrelevantes. Desea obtener pares de líneas que se vean así:Sink Input #12345 module-stream-restore.id = "whatever"
Suponiendo que las líneas van en pares,
read
hágalas de dos en dos con la opción adecuadaIFS
(#
para la primera línea de un par,=
para la segunda) para extraer datos relevantes. Utilice variables ficticias para las piezas que no necesita.- Trabajar con datos extraídos. Tenga en cuenta que
IFS='='
para la segunda línea de un par se extraerá todo lo que esté después de=
, es decir, el espacio adyacente y también las comillas dobles. Es por eso que en el código (a continuación) comparo con' "sink-… [snapclient]"'
, no solo con'sink-… [snapclient]'
.
El 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