如何解决从另一个命令启动的 ssh-add 捕获输出
这是我的问题的完整版本。我将所有这些细节都包括在内,以防我的预感是错误的,但您可能想跳到下面的 tl;dr。
我正在尝试编写一个运行任意命令并捕获是否有任何输出打印到终端的函数。我不想干扰正在打印的输出。如果这是一个相关的并发症(可能不是),我也想在命令的退出代码上进行分支。
这是我所拥有的:
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;dr(我认为!)
我认为这个问题归结为:为什么 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.
解决方法
为什么 log.txt 中没有密码提示?
提示是从 openssh load_identify_file 和 readpass.c read_passphrase() 打印出来的。该函数对 _PATH_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 并使用 {{1 }} 在那个 chroot 里面。这个想法是该进程将看到 proot
文件被替换的 chroot 并将写入您的文件描述符而不是终端。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。