У меня есть простой скрипт оболочки для запуска в Android adb shell.
while true; do
read var1
echo $var1 > /data/local/tmp/debug.txt
am force-stop $var1
done
Работает нормально, если я ввожу значение в консоль исходного экземпляра оболочки. Но если я открою другую оболочку adb и попытаюсь передать данные в первый процесс:
echo "com.package.name" > /proc/XXXX/fd/0
где XXXX - это pid первой оболочки, я вижу только, что строка "com.package.name" приходит в read
, но ни echo
строка отладки, ни am
строка не выполняются. То есть скрипт, похоже, ждет чего-то, возможно, символа новой строки, но добавление \n
, -e
аргумента и прочего во входные данные второй оболочки не помогло.
Как правильно передавать данные между скриптами оболочки?
решение1
Вас подстерегает обычная концепция, чтовсе в системе Linux является файлом. Чтобы проиллюстрировать это, я поместил ваши команды в файл с именем forever
, затем нашел PID процесса, затем
$ file /proc/25546/fd/*
/proc/25546/fd/0: symbolic link to `/dev/pts/12'
/proc/25546/fd/1: symbolic link to `/dev/pts/12'
/proc/25546/fd/2: symbolic link to `/dev/pts/12'
/proc/25546/fd/255: symbolic link to `/home/me/tmp/forever'
$ file /dev/pts/12
/dev/pts/12: character special
Это показывает, что ваши файловые дескрипторы 1,2,3 являются символьными файлами. Теперь, это хорошо известно (см. напримерэтот ответ на Unix и Linux) что:
Символьные устройства (также называемые символьными специальными файлами) ведут себя как каналы, последовательные порты и т. д.: запись или чтение в них — немедленное действие. Но то, что драйвер делает с данными,свой собственный бизнесЗапись байта на символьное устройство может привести к его отображению на экране, выводу на последовательный порт, преобразованию в звук, ... Чтение байта с устройства может привести к тому, что последовательный порт будет ожидать ввода, может вернуть случайный байт (/dev/urandom), ...
Поэтому вам нужен другой способ реализации IPC (межпроцессного взаимодействия).В Unix и Linux, есть именованные каналыдля этого. Измените ваш скрипт следующим образом:
#!/bin/bash
MYPIPE=/tmp/my_pipe
if [[ ! -p $MYPIPE ]]; then
mkfifo $MYPIPE
fi
while true
do
if read line <$pipe; then
if [[ "$line" == 'quit' ]]; then
break
fi
echo $line >> /tmp/debug.txt
fi
done
echo "I quit"
Запустите скрипт; с другого терминала введите
$ cat > /tmp/my_pipe
My name is
George Washington
....
На третьем терминале с помощью tail -f /tmp/debug.txt
, вы увидите то, что только что ввели во второй терминал, снова появившийся из /tmp/debug.txt
.
На андроиде, ситуация немного сложнее, но вы обнаружите,здесьиздесьдва различных способа обойти проблему создания именованных каналов на нерутированном Android-устройстве (первый проще второго).