Shell 伊皮顿赢了';t捕获一些命令输出(例如,ack)
我不明白为什么IPython不将某些系统命令的结果分配给python变量。这似乎经常发生在我和可执行文件上 例如,以下命令生成输出:Shell 伊皮顿赢了';t捕获一些命令输出(例如,ack),shell,ipython,Shell,Ipython,我不明白为什么IPython不将某些系统命令的结果分配给python变量。这似乎经常发生在我和可执行文件上 例如,以下命令生成输出: In [1]: !ack --nocolor foo bar 1:foo 然而,每当我将结果保存到一个变量时,就会得到一个空输出 In [2]: out=!ack --nocolor foo In [3]: out Out[3]: [] 即使我尝试了各种黑客,我也会遇到这个问题: In [4]: out=!ack --nocolor foo > tmp
In [1]: !ack --nocolor foo
bar
1:foo
然而,每当我将结果保存到一个变量时,就会得到一个空输出
In [2]: out=!ack --nocolor foo
In [3]: out
Out[3]: []
即使我尝试了各种黑客,我也会遇到这个问题:
In [4]: out=!ack --nocolor foo > tmp; sleep 1; cat tmp
In [5]: out
Out[5]: []
事实上,tmp
在最后一种情况下是空的,这表明输出捕获会弄乱这些命令
有人知道如果这是IPython或ack/ag的问题,或者仅仅是我对IPython在这里应该如何表现的误解吗?我已经推断出
out=!cmd
使用%sx
。这与不同!cmd
已运行(请参阅文档了解%sw
和%system
)
%sx
经过几层函数,最后调用
# import IPython
IPython.utils._process_common.process_handler
其代码类似于@Elliott Frisch在其已删除答案中使用的子流程
调用:
p = subprocess.Popen("ack --nocolor foo", stdout=subprocess.PIPE, shell=True)
(output, err) = p.communicate()
我将流程处理程序
代码抽象为:
def cmd1(astr='ack --nocolor 15 *.txt'):
callback = lambda p: p.communicate()
stderr = subprocess.PIPE
stderr = subprocess.STDOUT
shell = True
close_fds = True
executable = None
p = subprocess.Popen(astr,
shell=shell,
executable=executable,
#stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=stderr,
close_fds=close_fds,
)
out = callback(p)
return out, p.returncode
这项工作:
In [40]: cmd1()
Out[40]:
((b'stack53269737.txt:2:11 12 13 14 15 16\ntest.txt:3:11\t12 13 14 15\ntest1.txt:5: 0.054181, 0.506962, 0.315159, 0.653104\n',
None),
0)
但是如果我取消注释stdin
行,它将失败:
In [42]: cmd1()
Out[42]: ((b'', None), 1)
所以是
stdin=subprocess.PIPE,
导致ack
调用失败的参数。它不会导致其他常见shell命令出现问题,如ls
或grep
ack
帮助包括:
--[no]filter Force ack to treat standard input as a pipe
(--filter) or tty (--nofilter)
将--nofilter
添加到我的命令中(--nocolor
不需要此重定向):
因此,这就是关键-强制
ack
忽略管道输入(尽管我不完全理解细节)。out=!确认--thpppt
有效<代码>!确认…>tmp后接out=!cat tmp
(单独一行)适用于我。显然,howout=
收集输出以及ack
如何生成输出,但发现这一点可能需要深入挖掘其中一个的代码。经过一些挖掘和实验,我推断您需要在ack
命令中添加一个--nofilter
标志。我对out=”没有问题!ag….
非常感谢,@hpaulj,这非常有用!所以,据我所知,当我们运行out=!ack foo
,它大致被转换为cat/dev/stdin | ack foo
,不幸的是,它的行为与ack foo
非常不同。因此,如果可以在标准输入中记录iPython管道,那就太好了!顺便说一下,ack的手册页(v.2.24)也让我感到困惑:“如果没有指定要搜索的文件,无论是在命令行上还是通过“-x”选项导入,ack都会深入到子目录中选择要搜索的文件。”。这是不正确的:ack
实际上尝试在STDIN中搜索,如果它是管道输入的。我不擅长此子流程和shell内容,但我怀疑ipython
正在使用输入管道来允许^c中断<代码>进程\u处理程序有一个try
块来刷新和终止子进程。
In [50]: cmd1('ack --nofilter 15 *.txt')
Out[50]:
((b'stack53269737.txt:2:11 12 13 14 15 16\ntest.txt:3:11\t12 13 14 15\ntest1.txt:5: 0.054181, 0.506962, 0.315159, 0.653104\n',
None),
0)
In [51]: out = !ack --nofilter 15 *.txt
In [52]: out
Out[52]:
['stack53269737.txt:2:11 12 13 14 15 16',
'test1.txt:5: 0.054181, 0.506962, 0.315159, 0.653104',
'test.txt:3:11\t12 13 14 15']