#bash #shell #while-loop #moonlight
#bash #оболочка #цикл while #лунный свет
Вопрос:
Я написал скрипт с циклом while, не понимая сложности получения переменной из указанного цикла while.
Что я хочу сделать, так это запустить команду, которую цикл while сохраняет в переменной ‘stream’ (см. Код ниже) после того, как цикл while завершит столько циклов, сколько необходимо. Я использую этот скрипт для определения того, какие игровые контроллеры подключены, и создаю команду для инициализации moonlight, программы для raspberry pi, которая позволяет мне транслировать через Nvidia Game Stream с различными типами контроллеров.
#!/bin/bash
stream="moonlight stream -1080 -app Steam"
device=none
event=0
Player="-input /dev/input/event"
XbElite="-mapping /opt/retropie/configs/moonlight/XboxOne.map"
PlSt3="-mapping /opt/retropie/configs/moonlight/PS3.map"
XboxElite="N: Name="Microsoft X-Box One Elite pad""
PS3="N: Name="PLAYSTATION(R)3 Controller""
cat /proc/bus/input/devices |
while read CMD; do
line=$(echo "$CMD" | sed 's/ /\ /g; s/:/\:/g; s/(/\(/g; s/)/\)/g; s/-/\-/g; s/=/\=/g')
if [ "$line" = "$XboxElite" ]; then
echo Xbox
device=xboxElite
if [ "$device" = "xboxElite" ]; then
stream="$stream $XbElite $Player$event"
event=$((event 1))
device=none
fi
elif [ "$line" = "$PS3" ]; then
echo PS3
device=ps3
if [ "$device" = "ps3" ]; then
stream="$stream $PlSt3 $Player$event"
event=$((event 1))
device=none
fi
fi
done
echo $stream #put here as a placeholder to see the final command in the variable. Currently printing: 'moonlight stream -1080 -app Steam'
Я понимаю, что это, вероятно, не самый чистый способ сделать это или что код даже близко написан так хорошо, как мог бы быть, но поскольку у меня мало предыдущего опыта в кодировании любого рода, это то, что я мог бы сделать на данный момент.
Любая помощь будет принята с благодарностью!
Комментарии:
1. Проверьте информацию wooledge wiki или shellcheck по этой проблеме.
Ответ №1:
Ну, способ запустить ее как команду — просто удалить echo
:
done
$stream
… за исключением того, что вы не можете, потому while
что цикл находится на правой стороне канала. Это означает, что он выполняется в «подоболочке» и не может иметь побочных эффектов в своей родительской оболочке (вне цикла); после завершения цикла $stream
он вернется к тому, что было до цикла.
Чтобы сохранить цикл в той же среде, что и окружающий код, а не в его собственной подоболочке, вам нужно читать из файла напрямую, а не использовать канал:
# no `cat` command here. No pipe.
while read CMD; do
...
done </proc/bus/input/devices #this replaces the `cat |`.
$stream
В общем случае при динамическом создании команды для последующего запуска вы столкнетесь с проблемами с кавычками, пробелами или другими специальными символами. Проще всего избежать этих проблем, если вы создаете команду в массиве, а не в строке. Синтаксис для построения и выполнения команды внутри массива выглядит следующим образом:
stream=(moonlight stream -1080 -app Steam)
...
while read CMD; do
...
stream =("$XbElite" "$Player$event")
...
stream =("$PlSt3" "$Player$event")
...
done </proc/bus/input/devices
"${stream[@]}"
Комментарии:
1. Проблема, с которой я сталкиваюсь при этом, заключается в том, что как только цикл While заканчивается, переменная stream больше не изменяется, как это происходит внутри цикла.
2. Да, упустил из виду, что был канал. См. Редактирование — я только что добавил объяснение и исправление для этого.
3. Затем я получаю $stream, который затем записывается как: ‘moonlight stream -1080 -app Steam’ без добавления конфигураций контроллера, добавленных через цикл while.
4. похоже, вы все еще используете
cat |
. Нет каналов.
Ответ №2:
То, что сказал Марк Рид, а также основной цикл можно упростить:
sed 's/([-:( )=])/\amp;/g' /proc/bus/input/devices |
while read line; do
if [ "$line" = "$XboxElite" ]; then
echo Xbox
stream="$stream $XbElite $Player$event"
event=$((event 1))
elif [ "$line" = "$PS3" ]; then
echo PS3
stream="$stream $PlSt3 $Player$event"
event=$((event 1))
fi
done