这是我问题的完整版本。我包括所有这些细节,以防我的预感是错误的,但你可能想跳到tl;博士下面。
我正在尝试编写一个函数,该函数运行任意命令,并捕获是否将任何输出打印到终端。我不想干扰正在打印的输出。如果这是一个相关的复杂(可能不是),我还想分支到命令的退出代码。
我现在拥有的是:
function run_and_inspect {
# this subshell ensures the stdout of ${@} is printed and captured
if output=$(
set -o pipefail
"${@}" | tee /dev/tty
); then
did_cmd_work="yes"
else
did_cmd_work="no"
fi
if [ -z "$output" ]; then
was_there_output="no"
else
was_there_output="yes"
fi
echo "output?" $was_there_output
}
一般来说,这样做很好:
$ run_and_inspect true
output? no
$ run_and_inspect "echo hello"
hello
output? yes
但我找到了一个问题命令:
git pull | grep -v 'Already up to date.'
如果没有什么可拉的,这条管道通常不会产生输出。但是,如果ssh-add需要提示输入密码,就会有输出。只是没有被run_and_inspect
注意到
function git_pull_quiet {
git pull | grep -v 'Already up to date.'
}
$ run_and_inspect git_pull_quiet
Enter passphrase for key '/home/foo/.ssh/id_ed25519':
output? no
有输出到我的终端。我认为问题在于它不是来自git pull
管道的标准输出,这是run_and_inspect
所知道的。它是从哪里来的?我该怎么解决这个问题?我也尝试过重定向stderr (即git pull 2>&1
),但是没有运气。有什么方法可以直接监视/dev/tty吗?
tl博士(我想!)
我认为这个问题归结为:为什么密码在log.txt中没有提示?
$ git pull 2>&1 | tee log.txt
Enter passphrase for key '/home/foo/.ssh/id_ed25519':
Already up to date.
$ cat log.txt
Already up to date.
发布于 2021-03-01 00:29:05
为什么密码提示不在log.txt中?
提示符是用文件和passphrase()打印的。该函数使用TTY "/dev/tty“执行open(_PATH_TTY
,然后对其执行write()
。
输出直接显示给终端/dev/tty
,而不是标准流。
就像您使用tee /dev/tty
一样,这意味着您的函数也将无法工作。更愿意保持子程序的稳健性和缓冲性:
if { tmp=$("$@" > >(tee >(cat >&3))); } 3>&1; then
有什么方法可以直接监视/dev/tty吗?
编写您自己的终端模拟器并在其中生成您的进程,然后解析该终端模拟器中的所有输入。像screen
或tmux
这样的程序可能是有用的。
解决方法可以是下载proot
并打开文件描述符到某个文件,然后创建一个只有/dev/tty
文件符号链接到/proc/self/fd/<that file descriptor>
的chroot,然后在该chroot中运行带有proot
的进程。其思想是,进程将看到带有/dev/tty
文件的chroot被替换,并将写入文件描述符,而不是写入终端。
https://stackoverflow.com/questions/66404663
复制相似问题