Ich schreibe ein kleines Bash-Skript in Linux, um Pulseaudio-Ein-/Ausgänge zu steuern.
Ich möchte alle Sink-Eingänge, bis auf einen, in den einen oder anderen Sink leiten. Der Sink-Eingang, den ich nicht leiten möchte, ist dieser:
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]"
Um einen Sink-Eingang zu einem anderen Sink zu verschieben, muss ich diesen Befehl verwenden:
pactl move-sink-input <sink-input id> <sink id>
Ich muss also das Ergebnis des ersten Befehls analysieren, um das Sink Input #ID
(in der ersten Zeile enthaltene) zu erhalten, aber ich muss eine Bedingung verwenden, um zu prüfen, ob module-stream-restore.id
(letzte Zeile) wirklich das ist, was ich weiterleiten möchte.
Ich bräuchte sowas wie:
if [ <last line> = 'sink-input name I need' ]
then
pactl move-sink-input <id from first line> <my sink name>
fi
Ich weiß einfach nicht, wie ich den Befehl analysieren soll, um BEIDE Informationen zu erhalten.
Im Moment kann ich nur die letzte Zeile oder nur die #ID abrufen.
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
Wie gehe ich beim Analysieren des Ergebnisses vor, pactl list sink-inputs
sodass ich in jedem „Block“ (auch bekannt als jeder Sink-Eingabe) des Ergebnisses dieses Befehls in einem Bash-Skript zwei Elemente und nicht nur eines lesen kann?
Antwort1
Das Problem besteht darin, dass die in der do
Schleife festgelegten Variablen nicht von einem Durchlauf zum nächsten beibehalten werden.
Die einfache Lösung besteht darin, die Listenausgabe in einer temporären Datei zu speichern und sie dann zweimal zu scannen:-
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
Sie haben nun die beiden Variablen, die Sie benötigen, beide gesetzt. Es ist keine sehr elegante Lösung, aber sie ist unkompliziert und leicht zu verstehen und zu warten. Beachten Sie, dass ich sed
zur Ausführung der grep
Funktionen verwendet habe: Eine Anleitung zur Funktionsweise finden Sie unterHier.
Sie können die temporäre Datei jedoch mit einer komplizierteren Lösung vermeiden: -
Ids="$(pactl list short sink-inputs | \
sed -n -e 's/^Sink Input #\(.*\)$/\1/p' \
-e 's/.*module-stream-restore.id = "\(.*\)"$/\1/p')"
Sie haben jetzt beide Variablen in Ids
, getrennt durch eine neue Zeile: Sie können sie wie folgt trennen: -
streamId="${Ids%$'\n'*}"
Id="${Ids#*$'\n'}"
Wenn Sie auch keine temporären Variablen mögen, können Sie Id
anstelle von verwenden Ids
!
Ich habe dies getestet, indem ich Ihre Listenausgabe kopiert und diese anstelle eines echten pactl
Befehls verwendet habe. Daher sollte alles mit einem Live-Befehl funktionieren.
Antwort2
Das Konzept:
- Rufen Sie es
pactl …
mitLC_ALL=C
„Set“ auf, um eine lokalisierte Ausgabe zu vermeiden (Sie brauchen das offensichtlich nicht, aber im Allgemeinen ist es das). Verwenden Sie
egrep
diese Option, um irrelevante Zeilen zu verwerfen. Sie möchten Zeilenpaare erhalten, die wie folgt aussehen:Sink Input #12345 module-stream-restore.id = "whatever"
Angenommen, die Zeilen verlaufen paarweise,
read
dann verwenden Sie jeweils zwei mit der richtigen ReihenfolgeIFS
(#
für die erste Zeile in einem Paar,=
für die zweite), um relevante Daten zu extrahieren. Verwenden Sie Dummyvariablen für Teile, die Sie nicht benötigen.- Arbeiten Sie mit extrahierten Daten. Beachten Sie, dass
IFS='='
für die zweite Zeile in einem Paar alles nach dem extrahiert wird=
, also auch das angrenzende Leerzeichen und die Anführungszeichen. Aus diesem Grund vergleiche ich im Code (unten) mit' "sink-… [snapclient]"'
und nicht nur mit'sink-… [snapclient]'
.
Der Code:
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