2

据我所知,在 Python 中执行系统命令大约有 3 种方法:

  1. os.system(command) -> exit_status

  2. os.popen(command [, mode='r' [, bufsize]]) -> pipe

  3. commands.getoutput(command)-> string

现在我需要控制系统命令的执行器,除了:

os.system('su xxx;' + command)

有没有其他更优雅的方式来达到同样的效果?

4

3 回答 3

2

您提到的所有事情(顺便说一下,模块已经继承了subprocess这些事情)都是产生进程的方式。你听起来像是在寻找setuid。您可以调用一个函数来执行此操作(例如os.setuid),或者,通常情况下,取决于您的脚本所做的事情,您可以以提升的用户身份运行整个脚本。

于 2012-07-26T04:16:51.570 回答
1

subprocess使用模块以其他用户身份运行命令(实施@Julian 的建议)。它类似于@tMC 的代码,但级别更高:

import os
import pwd
from subprocess import check_output as qx

def change_user(uid, gid=None):
    if gid is None:
        gid = uid
    def preexec_fn():
        os.setgid(gid)
        os.setgroups([gid])
        os.setuid(uid)
    return preexec_fn

print(qx(['id']))
print(qx(['id'], preexec_fn=change_user(pwd.getpwnam('nobody').pw_uid), env={}))
print(qx(['id']))

在旧的 Python 版本中,您可能需要添加close_fds=True子进程调用以避免 fd 泄漏。

您可以使用cwd参数来指定运行命令的目录,例如用户的主目录。

填充env字典以设置子进程的环境变量。

于 2012-07-27T08:56:53.777 回答
0

虽然对于大多数实现来说可能是“低级”的,但对于一些人来说了解这在更高级别的模块中是如何真正发生的可能是有教育意义的。

import os
import pwd

pout, pin = os.pipe()                                # Creates an anonymous pipe used to communicate with the child process

if not os.fork():                                    # The fork() syscall duplicated the process retuning 0 to the new child process.
    os.closerange(0, 2)                              # Closing stdin, stdout and stderr- they were inherited from the parent process
    os.dup2(pin, 1)                                  # Copy the input side of the IPC pipe to stdout (always fd 1)
    os.setuid(pwd.getpwnam('nobody').pw_uid)         # Change our user id to that of the user `nobody`.  Also see `setgid()`
    os.execl('/bin/whoami', 'whoami')                # Now that we've connected out stdout to the pipe connected to the parent process
                                                     #     and changed our user id to that of the user we want to run the command with
                                                     #     we can `exec()` the new process; replacing our currently running process, 
                                                     #     inheriting the env.
    os._exit(0)                                      # Since we called `exec` above, this is never eval'd, but is good form

os.wait()                                            # Back at the parent process- `wait()` will, well, wait until the child process exits.
os.close(pin)                                        # Close the input side of the pipe, the parent shouldn't write to. (bi-dirctional IPC
                                                     #     would require 2 pipes.  One in each direction
child_stdout_pipe = os.fdopen(pout, 'r')             # Open the output side of the IPC pipe
child_process_output = child_stdout_pipe.read()      # ...and read from the pipe.  This should include anything that came from the stdout of
                                                     #     the child process.  Since we closed the input side of the pipe, the `read()` 
                                                     #     will read an EOF after all the data in the pipe is returned.

print child_process_output                           # Win! (`write()`ing out the parent stdout want we found in the pipe from the child proc
于 2012-07-26T19:21:45.547 回答