Bash:sudo -S

Bash:sudo -S

我正在尝试使用sudo通过-S命令行发出密码。

$ sudo -S <<< "mypassword" command

这可行,但不允许交互命令。例如nano

$ sudo -S <<< "mypassword" nano /tmp/foo

它会自动关闭 nano 会话。与以下相同apt-get

$ sudo -S <<< "mypassword" apt-get install foo

在我按“y”安装 foo 之前它就关闭了。我知道我可以-y通过 apt 来安装,但总的来说,这很令人沮丧。

也尝试了类似这样的方法,但仍然无法参与交互式会话:

$ sudo -S <<< "mypassword" -H -u root bash -c "apt-get install foo"

是否可以-S与 sudo 一起使用而不取消所有交互式 shell?

答案1

文件描述符是继承的

你正在使用的<<<aka此处字符串,这种重定向是通过立即取消链接(即删除)的临时文件实现的。还知道进程从父进程到子进程继承文件描述符(以及其中的标准输入) 1sudo -S ,当执行时,它会从原始 shell 传递给它的临时文件(读取命令的文件)中读取输入sudo -S。您可以看到实际效果:

$ sudo -S bash -c 'ls -l /proc/self/fd/0' <<< "mypasswd"
lr-x------ 1 root root 64 Feb 26 13:12 /proc/self/fd/0 -> '/tmp/sh-thd.cUOOXU (deleted)'

因此,在这种情况下nano会报告Too many errors from stdin错误。可以做的是手动重新连接stdin来自哪里。

$ sudo -S bash -c 'exec < /dev/tty; nano /tmp/foobar' <<< "mypasswd"

$ sudo -S bash -c 'nano /tmp/foobar < /dev/tty' <<< "mypasswd"

这两个命令中的任何一个都可以nano正常启动,其他命令也同样如此。/dev/tty是代表当前终端设备的特殊文件,它实际上与“正常”交互式 shell 相同stdin(当然,我过于简化了该陈述)。

主题的另一个变体是$ sudo -S bash -c 'nano /tmp/foobar 0>&1' <<<"mypasswd"stdout实际上指向相同的终端设备(除非您明确提供了重定向以使 stdout 指向其他地方)。因此,如果我们将stdinpoint 设为dup的 licate stdout,它实际上是与上述相同的解决方案。(如果您想知道为什么我突出显示dup部分,那是因为dup2()syscall 是负责所有文件描述符处理的人)


警告

但是,请注意,我不鼓励sudo -S在交互式 shell 中使用,因为密码将保留在 shell 的历史记录中

$ sudo -S bash -c 'sleep 3m' <<< "ohnomypassword"
^C
$ history 2
 2016  sudo -S bash -c 'sleep 3m' <<< "ohnomypassword"
 2017  history 2

sudo -S更适合与其他进程一起使用,其中sudo -S需要通过管道输入,理想情况下来自zenity --passworddialog --passwordbox "foobar text" 200 200(参见额外1额外2关于对话)。


1. 如果文件打开时O_CLOEXEC设置了标志,则通过标志类型生成的子进程或替换进程execve()将无法访问该文件描述符 - 也就是说它将被关闭execve()

相关内容