Shell 伊皮顿赢了';t捕获一些命令输出(例如,ack)

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

我不明白为什么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; 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
(单独一行)适用于我。显然,how
out=
收集输出以及
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']