向应用程序发送命令并通过 bash 中的文件描述符读取其输出
Sending commands to an application and reading its output via file descriptor in bash
bluetoothctl 是一个具有 shell 并接受输入命令的应用程序。我想从 linux 的 shell 任意地向它发送命令,我也想读取它的无颜色输出。我正在使用基于 debian 的 linux(Raspbian 破坏者),如果可能的话,我想从 bash shell 开始。
到目前为止我已经尝试过:
方法一(通过fd发送命令)
- 运行附加的过程:
$ bluetoothctl
- 然后从另一个终端:
$ echo "my command" > /proc/$(pidof bluetoothctl)/fd/0
and $ echo -e "my command\n" > /proc/$(pidof bluetoothctl)/fd/0
and $ echo -e "my command3" > /proc/$(pidof bluetoothctl)/fd/0
但是 my command
只是作为 bluetoothctl 的输出出现,甚至按下 'enter' 键我在程序终端的键盘根本不执行命令只是换行。
方法二(将输出写入文本文件)
- 运行 进程已分离:
$ bluetoothctl > my.output &
,但它立即从应用程序中退出
方法三(通过管道发送命令)
- 创建管道
mkfifo mypipe
- 将管道重定向到 bluetoothctl
cat mypipe | bluetoothctl > my.output
- 向管道
echo "my command" > mypipe
写入命令,但会立即关闭应用程序,应用程序没有时间异步处理命令。因此,不起作用。
我认为可行的解决方案是启动应用程序分离 $ bluetoothctl &
然后通过 /proc/$(pidof bluetoothctl)/fd/0
向它发送命令并通过 /proc/$(pidof bluetoothctl)/fd/1
和 [=23 读取它的标准输出和标准错误=] 但我完全迷路了。
我想执行并读取其输出的命令之一是 'scan on' 理想情况下,一个 bluetoothctl 实例将处理多个命令,而不仅仅是管道可以执行的命令。
有人可以建议如何通过 fd 发送命令,以及如何通过进程的另一个 fd 读取输出。如果可能,所有这些都在 bash shell 中。
coprocess 是适合这项工作的工具:
#!/usr/bin/env bash
case $BASH_VERSION in ''|[0-3].*|4.0*) echo "ERROR: bash 4.1+ required" >&2; exit 1;; esac
coproc btctl { bluetoothctl; }
echo "scan on" >&"${btctl[1]}"
while IFS= read -r -u "${btctl[0]}" line; do
echo "Read line from btctl: $line" >&2
done
为了每个人的利益:按照接受的答案,我已经解决了我的协处理问题,但是,我使用 /proc/$(pidof bluetoothctl)/fd/0
发送命令,因为它的某些异步特性更适合我的应用程序.然后将输出转移到一个文件中,并在读取时使用 sed 删除颜色。
#!/bin/bash
readOutput() {
echo "$(cat $TEMP/bluetoothctl.out | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g'"
}
executeCommandInExistingProcess() {
if [ -z "$(pidof bluetoothctl)" ]
then
exit -1
else
echo "" >&/proc/$(pidof bluetoothctl)/fd/0
fi
}
startParallelProcess() {
output="$TEMP/bluetoothctl.out"
if [ ! -z "$(pidof bluetoothctl)" ]
then
echo "Bluetooth process is running..."
exit -1
fi
if [ -f "$output" ]
then
rm $output
fi
coproc bctl { bluetoothctl > $output; }
[ "$#" -ge 1 -a ! -z "" ] && executeCommandInExistingProcess ""
sleep 30
if [ ! -z $(pidof bluetoothctl) ]
then
[ "$#" -ge 2 -a ! -z "" ] && executeCommandInExistingProcess ""
executeCommandInExistingProcess "quit"
fi
}
bluetoothctl 是一个具有 shell 并接受输入命令的应用程序。我想从 linux 的 shell 任意地向它发送命令,我也想读取它的无颜色输出。我正在使用基于 debian 的 linux(Raspbian 破坏者),如果可能的话,我想从 bash shell 开始。
到目前为止我已经尝试过:
方法一(通过fd发送命令)
- 运行附加的过程:
$ bluetoothctl
- 然后从另一个终端:
$ echo "my command" > /proc/$(pidof bluetoothctl)/fd/0
and$ echo -e "my command\n" > /proc/$(pidof bluetoothctl)/fd/0
and$ echo -e "my command3" > /proc/$(pidof bluetoothctl)/fd/0
但是my command
只是作为 bluetoothctl 的输出出现,甚至按下 'enter' 键我在程序终端的键盘根本不执行命令只是换行。
方法二(将输出写入文本文件)
- 运行 进程已分离:
$ bluetoothctl > my.output &
,但它立即从应用程序中退出
方法三(通过管道发送命令)
- 创建管道
mkfifo mypipe
- 将管道重定向到 bluetoothctl
cat mypipe | bluetoothctl > my.output
- 向管道
echo "my command" > mypipe
写入命令,但会立即关闭应用程序,应用程序没有时间异步处理命令。因此,不起作用。
我认为可行的解决方案是启动应用程序分离 $ bluetoothctl &
然后通过 /proc/$(pidof bluetoothctl)/fd/0
向它发送命令并通过 /proc/$(pidof bluetoothctl)/fd/1
和 [=23 读取它的标准输出和标准错误=] 但我完全迷路了。
我想执行并读取其输出的命令之一是 'scan on' 理想情况下,一个 bluetoothctl 实例将处理多个命令,而不仅仅是管道可以执行的命令。 有人可以建议如何通过 fd 发送命令,以及如何通过进程的另一个 fd 读取输出。如果可能,所有这些都在 bash shell 中。
coprocess 是适合这项工作的工具:
#!/usr/bin/env bash
case $BASH_VERSION in ''|[0-3].*|4.0*) echo "ERROR: bash 4.1+ required" >&2; exit 1;; esac
coproc btctl { bluetoothctl; }
echo "scan on" >&"${btctl[1]}"
while IFS= read -r -u "${btctl[0]}" line; do
echo "Read line from btctl: $line" >&2
done
为了每个人的利益:按照接受的答案,我已经解决了我的协处理问题,但是,我使用 /proc/$(pidof bluetoothctl)/fd/0
发送命令,因为它的某些异步特性更适合我的应用程序.然后将输出转移到一个文件中,并在读取时使用 sed 删除颜色。
#!/bin/bash
readOutput() {
echo "$(cat $TEMP/bluetoothctl.out | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g'"
}
executeCommandInExistingProcess() {
if [ -z "$(pidof bluetoothctl)" ]
then
exit -1
else
echo "" >&/proc/$(pidof bluetoothctl)/fd/0
fi
}
startParallelProcess() {
output="$TEMP/bluetoothctl.out"
if [ ! -z "$(pidof bluetoothctl)" ]
then
echo "Bluetooth process is running..."
exit -1
fi
if [ -f "$output" ]
then
rm $output
fi
coproc bctl { bluetoothctl > $output; }
[ "$#" -ge 1 -a ! -z "" ] && executeCommandInExistingProcess ""
sleep 30
if [ ! -z $(pidof bluetoothctl) ]
then
[ "$#" -ge 2 -a ! -z "" ] && executeCommandInExistingProcess ""
executeCommandInExistingProcess "quit"
fi
}