我正在尝试使用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 指向其他地方)。因此,如果我们将stdin
point 设为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 --password
或dialog --passwordbox "foobar text" 200 200
(参见额外1和额外2关于对话)。
1. 如果文件打开时O_CLOEXEC
设置了标志,则通过标志类型生成的子进程或替换进程execve()
将无法访问该文件描述符 - 也就是说它将被关闭execve()