管道 ssh sudo 的输出
Piping the output of ssh sudo
有时我需要在远程服务器上以 root 身份 运行 命令,并在我的本地服务器上解析命令的输出。远程服务器不允许通过 ssh
进行 root 登录,但是 sudo
配置为需要密码。我需要做的一个简化示例是
ssh remote sudo echo bar | tr bar foo
(显然,在这个简化的例子中,没有充分的理由需要在不同的机器上 运行 echo
到 tr
:这只是一个玩具示例来解释我我正在努力。)
如果我运行上面的命令,我得到一个错误,sudo 无法提示输入密码:
richard@local:~$ ssh remote sudo echo bar | tr bar foo
sudo: no tty present and no askpass program specified
我可以尝试解决此问题的一种方法是将 -t
选项添加到 ssh
。如果我这样做,sudo
会等待并接受密码,但是 ssh
的伪终端的输出会转到标准输出,这意味着 sudo 提示消息会通过管道传输到 tr
并且不显示给用户。如果用户不知道 sudo
正在等待密码,他们会认为脚本已挂起,将提示消息传递给管道可能会中断进一步的处理:
richard@local:~$ ssh -t remote sudo echo bar | tr bar foo
[sudo] posswood foo oichood:
foo
(这个公认的愚蠢示例显示提示已由 tr
命令处理,输出通过管道传输到。)
我看到的另一种尝试解决此问题的方法是将 -S
选项添加到 sudo
。如果我这样做,sudo
会在 stderr 上提示输入密码,因此提示不会通过管道传递。这很好,但是 sudo
也接受标准输入的密码,这意味着它会回显到终端,任何从用户的肩膀上看的人都可以看到它:
richard@local:~$ ssh remote sudo -S echo bar | tr bar foo
[sudo] password for richard: p8ssw0rd
foo
我发现用这两个选项解决问题的方法并不优雅,但如果用户第一次输入错误的密码,我的解决方法就会遇到问题。这本身就是一个问题。这方面的例子是:
richard@local:~$ echo "[sudo] password for $USER:"; \
ssh -t remote sudo echo bar | tail +2 | tr bar foo
richard@local:~$ (read -s password; echo $password; echo >&2) \
| ssh remote sudo -S echo bar | tr bar foo
我相信一定有一个好的解决方案,因为这似乎不是一件不寻常的事情。有什么想法吗?
我想出的最佳解决方案是使用 sudo -S
并禁用本地回显,这样在您输入密码时就不会显示密码:
$ { stty -echo; ssh remote sudo -S echo hello; stty echo; echo 1>&2; }
[sudo] password for user:
hello
这让 sudo 负责密码提示,因此如果用户输入错误的密码,它也能正常工作。
我认为使用 ssh -t
的任何解决方案都无法正常工作,因为它结合了 stderr 和 stdout。
有时我需要在远程服务器上以 root 身份 运行 命令,并在我的本地服务器上解析命令的输出。远程服务器不允许通过 ssh
进行 root 登录,但是 sudo
配置为需要密码。我需要做的一个简化示例是
ssh remote sudo echo bar | tr bar foo
(显然,在这个简化的例子中,没有充分的理由需要在不同的机器上 运行 echo
到 tr
:这只是一个玩具示例来解释我我正在努力。)
如果我运行上面的命令,我得到一个错误,sudo 无法提示输入密码:
richard@local:~$ ssh remote sudo echo bar | tr bar foo
sudo: no tty present and no askpass program specified
我可以尝试解决此问题的一种方法是将 -t
选项添加到 ssh
。如果我这样做,sudo
会等待并接受密码,但是 ssh
的伪终端的输出会转到标准输出,这意味着 sudo 提示消息会通过管道传输到 tr
并且不显示给用户。如果用户不知道 sudo
正在等待密码,他们会认为脚本已挂起,将提示消息传递给管道可能会中断进一步的处理:
richard@local:~$ ssh -t remote sudo echo bar | tr bar foo
[sudo] posswood foo oichood:
foo
(这个公认的愚蠢示例显示提示已由 tr
命令处理,输出通过管道传输到。)
我看到的另一种尝试解决此问题的方法是将 -S
选项添加到 sudo
。如果我这样做,sudo
会在 stderr 上提示输入密码,因此提示不会通过管道传递。这很好,但是 sudo
也接受标准输入的密码,这意味着它会回显到终端,任何从用户的肩膀上看的人都可以看到它:
richard@local:~$ ssh remote sudo -S echo bar | tr bar foo
[sudo] password for richard: p8ssw0rd
foo
我发现用这两个选项解决问题的方法并不优雅,但如果用户第一次输入错误的密码,我的解决方法就会遇到问题。这本身就是一个问题。这方面的例子是:
richard@local:~$ echo "[sudo] password for $USER:"; \
ssh -t remote sudo echo bar | tail +2 | tr bar foo
richard@local:~$ (read -s password; echo $password; echo >&2) \
| ssh remote sudo -S echo bar | tr bar foo
我相信一定有一个好的解决方案,因为这似乎不是一件不寻常的事情。有什么想法吗?
我想出的最佳解决方案是使用 sudo -S
并禁用本地回显,这样在您输入密码时就不会显示密码:
$ { stty -echo; ssh remote sudo -S echo hello; stty echo; echo 1>&2; }
[sudo] password for user:
hello
这让 sudo 负责密码提示,因此如果用户输入错误的密码,它也能正常工作。
我认为使用 ssh -t
的任何解决方案都无法正常工作,因为它结合了 stderr 和 stdout。