Разбор результата команды в скрипте bash для Linux

593
Gob Tron

Я пишу небольшой сценарий bash в Linux для управления входами / выходами Pulseaudio.

Я хочу направить все входы приемников, кроме одного, в тот или иной приемник. Ввод приемника, который я не хочу направлять, это:

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
Почему вы не сохраняете входной номер приемника в переменной? Nifle 6 лет назад 0
Вы можете получить первую и последнюю строки с помощью `head -n1` и` tail -n1` или `sed '1! D'` и` sed' $! D'` Paulo 6 лет назад 0
@Nifle, номер входа приемника может измениться в любое время. Gob Tron 6 лет назад 0
@ Пауло, сегодня вечером попробую. Это может быть только то, что мне нужно. Gob Tron 6 лет назад 0

2 ответа на вопрос

2
AFH

Проблема в том, что переменные, установленные в 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="$" Id="$" 

Если вам не нравятся временные переменные, вы можете использовать Idвместо Ids!

Я проверил это, скопировав вывод списка и использовав его вместо реальной pactlкоманды, поэтому все должно работать с живой командой.

2
Kamil Maciorowski

Концепт:

  1. Призовите pactl …с LC_ALL=Cнабором, чтобы избежать локализованного выхода (вы, очевидно, это не нужно, но в общем случае люди делают).
  2. Используйте egrepдля удаления неактуальных строк. Вы хотите получить пары строк, которые выглядят так:

    Sink Input #12345 module-stream-restore.id = "whatever" 
  3. Предполагая, что линии идут парами, readих две на две с правильным IFS( #для первой строки в паре, =для второй), чтобы извлечь соответствующие данные. Используйте фиктивные переменные для деталей, которые вам не нужны.

  4. Работа с извлеченными данными. Обратите внимание, что 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 

Похожие вопросы