Pulseaudio 입력/출력을 제어하기 위해 Linux에서 작은 bash 스크립트를 작성 중입니다.
내가 원하는 것은 하나를 제외한 모든 싱크 입력을 하나 또는 다른 싱크로 라우팅하는 것입니다. 라우팅하고 싶지 않은 싱크 입력은 다음과 같습니다.
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 …
현지화된 출력을 피하려면 set 으로 호출하십시오LC_ALL=C
(분명히 이것이 필요하지는 않지만 일반적으로 사람들은 필요합니다).관련 없는 줄을 삭제하는 데 사용합니다
egrep
. 다음과 같은 라인 쌍을 얻고 싶습니다.Sink Input #12345 module-stream-restore.id = "whatever"
라인이 쌍으로 이동한다고 가정하면 관련 데이터를 추출하기 위해
read
2x2로 적절하게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