2010-03-01 15 views
6

Tôi đang sử dụng tiến trình con của Python.Popen để thực hiện một số FTP bằng cách sử dụng ứng dụng nhị phân của hệ điều hành máy chủ. Tôi không thể sử dụng ftplib hoặc bất kỳ thư viện nào khác vì nhiều lý do.Tại sao cung cấp stdin để subprocess.Popen gây ra những gì được viết để stdout để thay đổi?

Hành vi của nhị phân dường như thay đổi nếu tôi đính kèm trình xử lý stdin vào đối tượng Popen. Ví dụ, sử dụng FTP client XP, mà chấp nhận một tập tin văn bản của lệnh đối với vấn đề:

>>>from subprocess import Popen, PIPE 
>>>p = Popen(['ftp','-A','-s:commands.txt','example.com'], stdout=PIPE) 
>>>p.communicate()[0] 
'Connected to example.com. 
220 ProFTPD 1.3.1 Server (Debian) ... 
331 Anonymous login ok, send your complete email address as your password 
<snip> 
ftp> binary 
200 Type set to I 
ftp> get /testfiles/100.KiB 
200 PORT command successful 
150 Opening BINARY mode data connection for /testfiles/100.KiB (102400 bytes) 
226 Transfer complete 
ftp: 102400 bytes received in 0.28Seconds 365.71Kbytes/sec. 
ftp> quit 
>>> 

Commands.txt:

binary 
get /testfiles/100.KiB 
quit 

Khi còn cung cấp thiết bị nhập chuẩn, tất cả các bạn nhận được trong stdout là:

>>>from subprocess import Popen, PIPE 
>>>p = Popen(['ftp','-A','-s:commands.txt','example.com'], stdin=PIPE, stdout=PIPE) 
>>>p.communicate()[0] 
'binary 
get /testfiles/100.KiB 
quit' 
>>> 

Ban đầu, tôi nghĩ đây là một điều không minh bạch của khách hàng XPpp, có lẽ biết nó không ở chế độ tương tác và do đó hạn chế đầu ra của nó. Tuy nhiên, cùng một hành vi xảy ra với ftp của OS X - tất cả các phản hồi của máy chủ bị thiếu từ stdout nếu stdin được cung cấp - điều này dẫn tôi đến đây nghĩ rằng đây là hành vi bình thường.

Trong Windows, tôi có thể sử dụng nút chuyển-s để tập lệnh có hiệu quả ftp mà không sử dụng stdin, nhưng trên nền tảng khác dựa trên vỏ cho loại tương tác đó.

Phiên bản Python là 2.6.x trên cả hai nền tảng. Tại sao sẽ cung cấp một xử lý cho stdout stdin thay đổi, và nơi có phản ứng máy chủ đi đến?

+0

Bạn đã cân nhắc sử dụng 'ftplib' chưa? http://docs.python.org/library/ftplib.html –

+0

lý do bạn không thể sử dụng ftplib là gì. nó đi kèm với phân phối Python của bạn phải không? – ghostdog74

Trả lời

4

Tôi nghĩ rằng tôi đã đọc ở đâu đó (nhưng không thể nhớ ở đâu) máy khách Windows ftp đến từ một trong những triển khai BSD gốc. Trong đó chắc chắn sẽ chia sẻ một số mối quan hệ với việc triển khai ftp của Mac OS X. Đối với tôi, điều này không liên quan đến Popen nhưng đối với việc triển khai chương trình ftp của khách hàng, điều này làm cho một số kiểm tra về ngữ cảnh mà nó được khởi chạy (để xem nó có tương tác với một con người hay một shell script) hay không, bằng cách sử dụng isatty (3) như đã đề cập với Ignacio trong câu trả lời của mình. Đây là thực hành phổ biến cho các chương trình có thể được sử dụng trong cả hai ngữ cảnh. Một ví dụ nổi tiếng là triển khai GNU grep cho tùy chọn --color = auto: nó sẽ colorize đầu ra chỉ khi stdout là một tty, và không nếu đầu ra của grep được đưa vào một lệnh khác.

+0

Có, tôi nghĩ bạn đúng về điều này. Khi tôi chạy mã làm việc như một dịch vụ Windows (mà cũng có một stdin không tương tác) tôi nhận được hành vi tương tự. Vì vậy, câu hỏi tiếp theo là - có một cách đa nền tảng 'lừa' thực thi mà nó đang nói đến một tty không? Tôi giả sử nó không thực sự cần bất kỳ tính năng của một tty để sản xuất sản lượng đầy đủ. – Matt

+0

Không phải là tôi biết. Tuy nhiên, lưu ý rằng không có lệnh ftp nền tảng chuẩn nào có giao diện thống nhất (tức là đối số dòng lệnh), do đó bạn sẽ gặp khó khăn khi viết mã di động với phương pháp này. Nếu kịch bản của bạn chỉ cần tải về một vài tập tin sử dụng ftp, tôi khuyên bạn nên sử dụng urllib hoặc urllib2: nhập khẩu urllib f = urllib.urlopen ('ftp://example.com/testfiles/100.KiB') data = f.read() –

+0

Tôi đã dành một số thời gian thử nghiệm với pexpect/wexpect, hứa hẹn sẽ là một giải pháp nền tảng độc lập hợp lý.Đáng tiếc là wexpect cần một console và chết khủng khiếp khi chạy như một dịch vụ Windows. – Matt

7

Chương trình có thể đang sử dụng isatty(3) để phát hiện sự hiện diện của một tty trên stdin.

Các vấn đề liên quan