我有一个简单的 shell 脚本可以在 Android adb shell 中运行。
while true; do
read var1
echo $var1 > /data/local/tmp/debug.txt
am force-stop $var1
done
如果我在原始 shell 实例的控制台中输入一个值,它就可以正常工作。但如果我打开另一个 adb shell 并尝试将数据传递到第一个进程:
echo "com.package.name" > /proc/XXXX/fd/0
其中 XXXX 是第一个 shell 的 pid,我只看到字符串“com.package.name”到达第一个 shell 的read
,但调试echo
行和am
行都没有执行。也就是说,脚本似乎在等待某些东西,也许是换行符,但将\n
、-e
参数和其他内容添加到第二个 shell 输入中没有帮助。
如何在 shell 脚本之间正确地传递数据?
答案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 上,情况稍微复杂一些,但你会发现这里和这里解决非 rooted Android 设备上创建命名管道的问题的两种不同方法(第一种方法比第二种更简单)。