Analizando el resultado de un comando en un script bash de Linux

Analizando el resultado de un comando en un script bash de Linux

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-inputspara 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 dobucle 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 sedpara realizar las grepfunciones: 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 Iden lugar de Ids!

Probé esto copiando el resultado de su lista y usándolo en lugar de un pactlcomando real, por lo que todo debería funcionar con un comando en vivo.

Respuesta2

El concepto:

  1. Invoque pactl …con LC_ALL=Cset para evitar la salida localizada (aparentemente no necesita esto, pero en general la gente sí lo necesita).
  2. Úselo egreppara descartar líneas irrelevantes. Desea obtener pares de líneas que se vean así:

    Sink Input #12345
            module-stream-restore.id = "whatever"
    
  3. Suponiendo que las líneas van en pares, readhágalas de dos en dos con la opción adecuada IFS( #para la primera línea de un par, =para la segunda) para extraer datos relevantes. Utilice variables ficticias para las piezas que no necesita.

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

información relacionada