2014-03-05 80 views
4

我有一個Python腳本,需要通過命令行與用戶交互,同時記錄任何輸出。Python腳本和linux shell之間的交互

我目前有這樣的:

# lots of code 

popen = subprocess.Popen(
    args, 
    shell=True, 
    stdin=sys.stdin, 
    stdout=sys.stdout, 
    stderr=sys.stdout, 
    executable='/bin/bash') 

popen.communicate() 

# more code 

此執行外殼命令(例如adduser的newuser02)只是因爲它會鍵入它時到終端,包括交互行爲。這很好。

現在,我想從Python腳本內記錄出現在屏幕上的所有內容。但我似乎無法讓這部分工作。

我已經嘗試過使用subprocess.PIPE的各種方式,但這通常會使交互性變得模糊,就像不輸出提示字符串一樣。

我也嘗試過各種方法直接改變sys.stdout的行爲,但作爲子進程直接寫入sys.stdout.fileno(),這一切都無濟於事。

+0

作爲一個側面說明,有沒有使用了'殼= TRUE'理由嗎?特別是當你啓動的東西本身是'/ bin/bash'?你基本上是告訴Python開始一個'bash'的副本,告訴它開始另一個'bash'的副本(大概是因爲你沒有顯示整個代碼)告訴它開始一個'adduser'副本。你可能不需要涉及一個shell,但我無法想象爲什麼你需要兩個shell。 – abarnert

+0

@abarnert:'executable'不會啓動一個新的'bash'過程:如果'shell = True',它告訴'subprocess'模塊使用它的值而不是'/ bin/sh'。 'args'大概是一些帶有bash-isms的shell命令,比如''use_tty&>/dev/null''。據我所知,意圖是:'script -c'/ bin/bash -c「$ args」'log'。雖然[我的答案顯示](http://stackoverflow.com/a/22265426/4279),你不一定需要一個額外的bash過程來在這裏運行一個命令。 – jfs

回答

0

這應該工作

import subprocess 
f = open('file.txt','w') 
cmd = ['echo','hello','world'] 
subprocess.call(cmd, stdout=f) 
+1

這不顯示控制檯中的輸出。這不適用於需要用戶輸入的命令,如'adduser' –

+0

您的問題表明您希望將輸出記錄到文件中。你想讓它在文件和控制檯中都被記錄嗎? –

+0

是的,這個想法是,在python腳本的最後,我有一個完整的日誌,包括腳本本身顯式生成的所有日誌。 –

2

Popen可能不是很適合,由於buffering issues互動節目等,由於這樣的事實some programs write/read directly from a terminal例如,取回密碼。請參閱Q: Why not just use a pipe (popen())?

如果你想模仿script utility那麼你可以使用pty.spawn(),看到代碼示例Duplicating terminal output from a Python subprocesslog syntax errors and uncaught exceptions for a python subprocess and print them to the terminal

#!/usr/bin/env python 
import os 
import pty 
import sys 

with open('log', 'ab') as file: 
    def read(fd): 
     data = os.read(fd, 1024) 
     file.write(data) 
     file.flush() 
     return data 

    pty.spawn([sys.executable, "test.py"], read) 

或者你可以使用pexpect更多的靈活性:

import sys 
import pexpect # $ pip install pexpect 

with open('log', 'ab') as fout: 
    p = pexpect.spawn("python test.py") 
    p.logfile = fout # or .logfile_read 
    p.interact() 

如果你的子進程不會緩衝它的輸出(或者它不會干擾交互),並且它的輸出打印到stdout或stderr,那麼你可以嘗試subprocess

#!/usr/bin/env python 
import sys 
from subprocess import Popen, PIPE, STDOUT 

with open('log','ab') as file: 
    p = Popen([sys.executable, '-u', 'test.py'], 
       stdout=PIPE, stderr=STDOUT, 
       close_fds=True, 
       bufsize=0) 
    for c in iter(lambda: p.stdout.read(1), ''): 
     for f in [sys.stdout, file]: 
      f.write(c) 
      f.flush() 
    p.stdout.close() 
    rc = p.wait() 

讀取標準輸出/標準錯誤分開,你可以使用teed_call()Python subprocess get children's output to file and terminal?