Bash:sudo -S <<< "mypassword" - 交互式 shell 问题

Lau*_*ura 1 command-line bash sudo redirect

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

$ sudo -S <<< "mypassword" command
Run Code Online (Sandbox Code Playgroud)

这有效,但它不允许交互式命令。像nano例如:

$ sudo -S <<< "mypassword" nano /tmp/foo
Run Code Online (Sandbox Code Playgroud)

它会自动关闭 nano 会话。同apt-get

$ sudo -S <<< "mypassword" apt-get install foo
Run Code Online (Sandbox Code Playgroud)

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

也尝试过这样的东西,但它仍然无法参与交互式会话:

$ sudo -S <<< "mypassword" -H -u root bash -c "apt-get install foo"
Run Code Online (Sandbox Code Playgroud)

是否可以在-S不取消所有交互式 shell 的情况下与 sudo一起使用?

Ser*_*nyy 6

文件描述符被继承

您使用的是<<<aka here-string,这种类型的重定向是通过立即取消链接(又名删除)的临时文件实现的。还知道进程从父级到子级继承文件描述符(以及其中的标准输入)1,当sudo -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)'
Run Code Online (Sandbox Code Playgroud)

因此,在这种情况下会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"
Run Code Online (Sandbox Code Playgroud)

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

该主题的另一个变体是$ sudo -S bash -c 'nano /tmp/foobar 0>&1' <<<"mypasswd"stdout有效地指向同一个终端设备(除非您明确提供了重定向以将 stdout 指向其他地方)。因此,如果我们stdin指出是 的duplicate 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
Run Code Online (Sandbox Code Playgroud)

sudo -S更适合与其他进程一起使用,sudo -S希望通过管道输入,理想情况下来自zenity --passworddialog --passwordbox "foobar text" 200 200(请参阅关于对话框的extra1extra2)。


1. 如果文件在O_CLOEXEC标志设置的情况下打开,则通过execve()标志类型产生的子进程或替换进程将无法访问该文件描述符 - 即它将被关闭execve()