向bash shell发送多个共享环境的命令

3 投票
1 回答
2981 浏览
提问于 2025-04-17 19:48

我正在尝试按照这个答案来做:https://stackoverflow.com/a/5087695/343381

我需要在一个环境中执行多个bash命令。我的测试案例很简单:

import subprocess
cmd = subprocess.Popen(['bash'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

# Write the first command
command = "export greeting=hello\n"
cmd.stdin.write(command)
cmd.stdin.flush() # Must include this to ensure data is passed to child process
result = cmd.stdout.read()
print result

# Write the second command
command = "echo $greeting world\n"
cmd.stdin.write(command)
cmd.stdin.flush() # Must include this to ensure data is passed to child process
result = cmd.stdout.read()
print result

我原本期待的结果是(根据参考的答案)能看到“hello world”被打印出来。但实际上发生的情况是,它在第一个 cmd.stdout.read() 这里卡住了,根本没有返回。

有没有人能解释一下为什么 cmd.stdout.read() 从来没有返回?

备注:

  • 我必须从python中在同一个环境下运行多个bash命令。因此,subprocess.communicate() 并不适用,因为它会等待进程结束。
  • 需要注意的是,在我的实际测试案例中,并不是一组固定的bash命令要执行。逻辑是更动态的。我不能选择一次性运行所有命令。

1 个回答

2

你这里有两个问题:

  1. 你第一个命令没有任何输出。所以第一次读取会一直等着有输出。
  2. 你用的是read()而不是readline() -- read()会一直等到有足够的数据才会继续。

下面这个修改过的代码(根据Martjin的建议进行了轮询)运行得很好:

import subprocess
import select

cmd = subprocess.Popen(['bash'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

poll = select.poll()
poll.register(cmd.stdout.fileno(),select.POLLIN)

# Write the first command
command = "export greeting=hello\n"
cmd.stdin.write(command)
cmd.stdin.flush() # Must include this to ensure data is passed to child process
ready = poll.poll(500)
if ready:
   result = cmd.stdout.readline()
   print result

# Write the second command
command = "echo $greeting world\n"
cmd.stdin.write(command)
cmd.stdin.flush() # Must include this to ensure data is passed to child process
ready = poll.poll(500)
if ready:
   result = cmd.stdout.readline()
   print result

上面的代码设置了500毫秒的超时,你可以根据需要调整这个时间。

撰写回答