我想从 Python 调用一个程序并让它相信它的 stdout即使 Python 的进程标准输出附加到管道,它也是一个 tty。所以我使用了 pty.spawn功能来实现这一点,可以从以下方面进行验证:
$ python -c "import sys; from subprocess import call; call(sys.argv[1:])" python -c "import sys; print sys.stdout.isatty()" | cat
False
$ python -c "import sys; import pty; pty.spawn(sys.argv[1:])" python -c "import sys; print sys.stdout.isatty()" | cat
True
pty.spawn那么它的输入不会被回显,而是被重定向到主控的标准输出。这可以通过以下命令看到:$ python -c "import sys; import pty; pty.spawn(sys.argv[1:])" cat > out.txt
$ # Typed "hello" in input, but that is not echoed (use ^D to exit). It is redirected to output.txt
$ cat out.txt
hello
hello
subprocess.call时不存在这个问题$ python -c "import sys; from subprocess import call; call(sys.argv[1:])" cat > out1.txt
hello
$ cat out1.txt
hello
stdout作为 tty(类似于 pty.spawn )但它的输入被正确响应(类似于 subprocess.call )。有任何想法吗?
最佳答案
您正在创建一个带有连接到文件的 stdout 的终端,因此终端所做的正常回显将被发送到文件而不是屏幕。
我不确定 spawn旨在像这样直接使用:pty图书馆提供 pty.fork()创建子进程并返回标准输入/标准输出的文件描述符。但是你需要更多的代码来使用它。
要解决您当前遇到的问题 spawn ,这里有两个简单的选择:
选项 1:如果您只关心将生成的命令的输出发送到文件,那么您可以这样做(我更喜欢命名管道和 here python 单行文件):
$ python <(cat << EOF
import sys
import pty
print 'start to stdout only'
pty.spawn(sys.argv[1:])
print 'complete to stdout only'
EOF
) bash -c 'cat > out.txt'
start to stdout only
hello
complete to stdout only
$ cat out.txt
hello
python <(cat << EOF
import sys
import pty
import os
old_stdout = sys.stdout
sys.stdout = myfdout = os.fdopen(4,"w")
print 'start to out file only'
myfdout.flush()
pty.spawn(sys.argv[1:])
print 'complete to out file only'
sys.stdout = old_stdout
EOF
) bash -c 'cat >&4' 4>out.txt
hello
$ cat out.txt
start to out file only
hello
complete to out file only
pty库功能强大:它创建了一个附加到 python 进程 stdout 和 stdin 的终端设备。我想这个的大多数用途将使用 pty.fork()调用以便真正的标准输入/标准输出不受影响。pty.spawn 内的某处。调用,以便创建的 pty 仍然与实际终端 stdout 有明确的连接(当它尝试在您键入时回显 stdin 时)pty.spawn 的 pty通过更改其标准输出或与真实终端断开连接来创建。这允许标准输入的回显正常工作。pty库并为您提供更多控制权,但您会发现其中大部分都使用 pty.fork() (有趣的是,我还没有找到真正使用 pty.spawn 的)import sys
import pty
import os
import select
import time
import tty
import termios
print 'start'
try:
pid, fd = pty.fork()
print 'forked'
except OSError as e:
print e
if pid == pty.CHILD:
cmd = sys.argv[1]
args = sys.argv[1:]
print cmd, args
os.execvp(cmd,args)
else:
tty.setraw(fd, termios.TCSANOW)
try:
child_file = os.fdopen(fd,'rw')
read_list = [sys.stdin, child_file]
while read_list:
ready = select.select(read_list, [], [], 0.1)[0]
if not ready and len(read_list) < 2:
break
elif not ready:
time.sleep(1)
else:
for file in ready:
try:
line = file.readline()
except IOError as e:
print "Ignoring: ", e
line = None
if not line:
read_list.remove(file)
else:
if file == sys.stdin:
os.write(fd,line)
else:
print "from child:", line
except KeyboardInterrupt:
pass
pty.fork()pty.fork()怎么了示例作品:pty.fork() 的调用时,处理分为两部分:现在有两个线程似乎都刚刚执行了 pty.fork()称呼。pid和 fd当您从 fd 读取时,将设置为子进程 ID 和连接到子进程标准输入和标准输出的文件描述符:在父进程中您正在阅读写入 child 标准输出的内容;当您写信给 fd 时你正在给 child 的标准输入写信。所以现在,在父线程中,我们有一种通过其 stdout/stdin 与另一个线程通信的方法。pid设置为 0 和 fd未设置。如果我们想与父线程对话,我们可以读取和写入 stdin/stdout,知道父线程可以并且应该对此做些什么。pid 中的值判断我们是在父线程还是子线程中。 .如果我们想在子线程和父线程中做不同的事情,那么我们只需要一个条件语句,将子线程发送到一个代码路径,将父线程发送到不同的代码路径。这就是这条线的作用:if pid == pty.CHILD:
#child thread will execute this code
....
else
#parent thread will execute this code
...
os.execvp使用此方法是因为我们将使用此方法对作为终端的 pty 进行更多控制,但本质上与 pty.spawn()'. This means the child stdin/stdout are now connected to the command you wanted via a pty. IMmportantly, any input or output from the command (or the pty for that matter) will be available to the parent thread by reading from 相同。 fd . And the parent can write to the command via pty by writing to fd`fd 将真正的 stdin/stdout 连接到子级 stdin/stdout。 .这就是父代码现在所做的(else 部分)。任何出现在真实标准输入上的数据都被写出到 fd .从 fd 读取的任何数据(由 parent )写入标准输出。因此,父线程现在唯一要做的就是在真正的 stdin/stdout 和 fd 之间进行代理。如果您想以编程方式对命令的输入和输出执行某些操作,这就是您可以执行的操作。tty.setraw(fd, termios.TCSANOW)
关于Python pty.spawn stdin 未回显但重定向到 master 的 stdout,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43293771/
我想使用spawn(针对多个并发子进程)在Ruby中执行一个外部进程,并将标准输出或标准错误收集到一个字符串中,其方式类似于使用Python的子进程Popen.communicate()可以完成的操作。我尝试将:out/:err重定向到一个新的StringIO对象,但这会生成一个ArgumentError,并且临时重新定义$stdxxx会混淆子进程的输出。 最佳答案 如果你不喜欢popen,这是我的方法:r,w=IO.pipepid=Process.spawn(command,:out=>w,:err=>[:child,:out])
我想知道Ruby用来在命令行打印这些东西的输出流:irb(main):001:0>a="test"=>"test"irb(main):002:0>putsatest=>nilirb(main):003:0>a=>"test"$stdout是否用于irb(main):002:0>和irb(main):003:0>?而且,在这两次调用之间,$stdout的值是否有任何变化?另外,有人能告诉我打印/写入这些内容的Ruby源代码吗? 最佳答案 是的。而且很容易向自己测试/证明。在命令行试试这个:ruby-e'puts"foo"'>test.
我正在尝试将$stdout设置为临时写入一个文件,然后返回到一个文件。test.rb:old_stdout=$stdout$stdout.reopen("mytestfile.out",'w+')puts"thisgoesinmytestfile"$stdout=old_stdoutputs"thisshouldbeontheconsole"$stdout.reopen("mytestfile1.out",'w+')puts"thisgoesinmytestfile1:"$stdout=old_stdoutputs"thisshouldbebackontheconsole"这是输出。r
我想从rubyrake脚本运行一个可执行文件,比如foo.exe我希望将foo.exe的STDOUT和STDERR输出直接写入我正在运行rake任务的控制台.当进程完成时,我想将退出代码捕获到一个变量中。我如何实现这一目标?我一直在玩backticks、process.spawn、system但我无法获得我想要的所有行为,只有部分更新:我在Windows上,在标准命令提示符下,而不是cygwin 最佳答案 system获取您想要的STDOUT行为。它还返回true作为零退出代码,这可能很有用。$?填充了有关最后一次system调
我正在编写一个ruby程序,它应该执行另一个程序,通过stdin向它传递值,从它的stdout读取响应,然后打印响应。这是我目前所拥有的。#!/usr/bin/envrubyrequire'open3'stdin,stdout,stderr=Open3.popen3('./MyProgram')stdin.puts"helloworld!"output=stdout.readerrors=stderr.readstdin.closestdout.closestderr.closeputs"Output:"puts"-------"putsoutputputs"\nErrors:"p
Activeadmingem已添加到我的rails项目中,但每次我尝试安装railsgactive_admin:install时,我都会收到类似的错误git://github.com/activeadmin/activeadmin.git(atmaster)isnotyetcheckedout.Runbundleinstallfirst.我肯定在运行“railsgactive_admin:install”之前运行了bundle。运行“bundleshow”后,我看到我已将“*activeadmin(1.0.0.pre3f916d6)”添加到我的项目中,但不断收到此错误消息。我的gem文
我有一个使用Jekyll托管在GitHub上的静态网站。问题是,我真的不需要master分支,因为存储库唯一包含的是网站。这样我就必须gitcheckoutgh-pages,然后gitmergemaster,然后gitpushorigingh-pages。有什么简单的方法可以摆脱gh-pages分支并直接从master推送? 最佳答案 Theproblemis,Idon'treallyneedthemasterbranch,astheonlythingtherepositorycontainsisthewebsite.Isthere
我在nginx+unicorn后面运行一系列Rails/Sinatra应用程序,零停机部署。我喜欢这个设置,但Unicorn需要一段时间才能完成重新启动,所以我想在完成时发送某种通知。我能在Unicorn文档中找到的唯一回调与workerfork相关,但我认为这些回调对此不起作用。这是我从赏金中寻找的东西:老unicorn主人启动新主人,然后新主人开始它的worker,然后旧主人停止它的worker并让新主人接管。我想在交接完成后执行一些ruby代码。理想情况下,我不想为此实现任何复杂的流程监控。如果这是唯一的方法,那就这样吧。但在走那条路之前,我正在寻找更简单的选择。
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。使用Railsv2.1,假设您有一个可从多个位置访问的Controller的操作。例如,在Rails应用程序中,您有一个链接可以从两个不同的View编辑用户,一个在用户索引View中,另一个在另一个View中(比方说从每个页面上的导航栏)。我想知道根据用户点击的链接将用户重定向回正确位置的最佳方法是什么。例如:示例1:列出所有用户点击列表中用户的“编辑”
我正在使用一个用RubyonRails构建的应用程序,目前错误处理非常差。如果通过ajax执行Controller方法,并且该方法导致500(或404或任何其他响应),则呈现500.html页面并将其作为AJAX请求的结果返回。显然,javascript不知道如何处理该HTML,网页看起来只是在等待响应。在AJAX调用期间发生错误时,rails是否有一种简单的方法来呈现error.rjs模板? 最佳答案 您可以在Controller的rescue_action或rescue_action_in_public方法中使用respond_