powershell stderr重定向每隔几个字符就换行

时间:2018-10-29 04:53:04

标签: python powershell redirect pyqt5 stderr

更新:这似乎特定于PyQt5的插槽/信号流(在Python 3.7.0中运行的PyQt 5.11)调用的函数中未捕获的异常。请参阅此问题文本的更深处的更新。


总体目标是在Windows 10计算机上准备python程序的stdout和stderr进行筛选并查找到相同的文件;我宁愿在操作系统级别进行此重定向(即,调用python的shell-在这种情况下为Windows);从python程序中干净地完成它并没有成功。

查看下面断开的stderr重定向行。

radiolog.py是一个大型python程序,在这里不应该涉及;在其中触发一个异常,以测试此日志记录工作流程。 radiolog_log.ps1是围绕radiolog.py的Powershell包装:

python -u radiolog.py 2>&1 | % ToString | Tee-Object log.txt

从powershell终端内部运行radiolog_log.ps1:

PS C:\Users\caver\Documents\GitHub\radiolog> .\radiolog_log.ps1
6319:Operating system is Windows.
6319:PowerShell.exe is in the path.
... (omitting a bunch of irrelevant radiolog transcript output)
6329:Accepted2
Traceback (most recent call last):
  File "
radiolog.py", line 3796, in keyPress
Eve
n
t
    sel
f.accept
(
)
  File "
r
adio
l
og.
py"
,
 line 3
9
13, in accept
    rprint(1/0)
ZeroD
ivi
sionError: division by zero

PS C:\Users\caver\Documents\GitHub\radiolog>

在控制台的宽度上有一些关于Powershell stderr重定向分割线的好帖子和答案...但是,这似乎是每隔几个字符就分割线,而且每次都不一样。< / p>

%ToString摆脱了Powershell异常处理的冗余层(在这种情况下);没有| %ToString看起来像这样(以'python:Traceback'开头的所有内容都是红色文本):

6851:Accepted2
python : Traceback (most recent call last):
At line:1 char:1
+ python -u radiolog.py 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Traceback (most recent call last)::String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

  F
ile "radiolog.py", line 3796, in keyPressEvent
    self.accept()
  File "ra
diol
o
g.p
y",
lin
e 39
13, in accept
    rp
r
int(1/0)
Ze
r
oDivisio
n
Error:
div
i
sion by zero
PS C:\Users\caver\Documents\GitHub\radiolog>

另一种尝试是从powershell终端运行.bat文件,然后在powershell中进行发球。

radiolog_log.bat:

python -u radiolog.py 2>&1

在powershell终端中:

PS C:\Users\caver\Documents\GitHub\radiolog> .\radiolog_log.bat | % ToString | Tee-Object log.dat

这将导致以下终端显示-一切正常:

C:\Users\caver\Documents\GitHub\radiolog>python -u radiolog.py  2>&1
8314:Operating system is Windows.
8314:PowerShell.exe is in the path.
...
8327:Accepted2
Traceback (most recent call last):
  File "radiolog.py", line 3796, in keyPressEvent
    self.accept()
  File "radiolog.py", line 3913, in accept
    rprint(1/0)
ZeroDivisionError: division by zero
PS C:\Users\caver\Documents\GitHub\radiolog>

但是log.dat是用unicode编写的,即,作为纯文本文件不是人类可读的。 Microsoft在Tee文档here中说了很多-不知道为什么...?找到了一个有关即时将其转换为ascii的问题,但是,看起来好像您不能拥有相同的实时文件和终端输出,因此一开始就否定了tee的大部分理由。

关于如何使一切像在Linux中一样好玩的任何想法吗?


更新:PyQt5插槽/信号流似乎正在触发此行为。示例代码,从原始radiolog.py大量缩减:

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

import sys

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        self.pushButton = QPushButton(Dialog)
        self.pushButton.setObjectName("pushButton")
        self.pushButton.setText(" Add Entry ")
        self.horizontalLayout = QHBoxLayout(Dialog)
        self.horizontalLayout.addWidget(self.pushButton)

class MyWindow(QDialog,Ui_Dialog):
    def __init__(self,parent):
        QDialog.__init__(self)
        self.ui=Ui_Dialog()
        self.ui.setupUi(self)

# click the button to see that stderr inserts line breaks every few
#   characters (different on each occurrance) when openNewEntry is called
#   from the slot/signal flow:      
        self.ui.pushButton.clicked.connect(self.openNewEntry)

# uncomment the following line to see that stderr is line-buffered when
#  openNewEntry is called from code:
#       self.openNewEntry()

    def openNewEntry(self):
        print(1/0)

def main():
    app = QApplication(sys.argv)
    w = MyWindow(app)
    w.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

在powershell终端中,按照对此问题的最早答案定义了STD-Handler(不需要观察虚线,但是,它确实可以在没有powershell-exception标头的情况下提供更清晰的输出,并且可以使-文本日志文件),然后执行以下操作:

python -u r.py *>&1 | STD-Handler log.txt

单击GUI中的按钮,您将获得以下信息:

[636765635572699130]: Traceback (most recent call last):
[636765635572808866]:
[636765635572918571]:  File "r.py", line 33,
[636765635573028268]:
[636765635573118026]: in open
[636765635573207784]: New
[636765635573307659]: E
[636765635573407558]: ntry
    print(1/0)
ZeroDivisionError: division by z
[636765635573506983]: ero

现在按照注释取消注释python代码中的行,以便从代码而不是从用户交互中调用异常;在powershell终端上运行同一行,您会得到以下提示:

[636765639350787977]: Traceback (most recent call last):
[636765639350877842]:   File "r.py", line 42, in <module>

[636765639350997857]:
[636765639351077838]: main()
  File "r.py", line 37, in main

[636765639351187538]:
[636765639351282570]: w = MyWindow(app)
  File "r.py", line 30, in __init__

[636765639351372787]:
[636765639351467301]: self.openNewEntry()
  File "r.py", line 33, in openNewEntry

[636765639351554768]:
[636765639351660016]: print(1/0)
ZeroDivisionError: division by zero

所以,这可能给PyQt社区带来了一个新问题,我将在不久的将来将其汇总起来并在此处进行交叉引用-尽管对该线程的帮助仍然非常棒!

2 个答案:

答案 0 :(得分:0)

我试图用一些虚拟脚本复制此问题,但是在两种情况下(ps和bat)都得到了正确的文件和终端输出。我想您可以只使用bat脚本,然后最后修复文件编码。如果您确实需要实时更新文件,则可以采用以下解决方法。基本上,您可以创建一些自定义“ Tee对象”并处理标准输出。 $ _是一个来自管道(stdout)的对象,即使它损坏了,您也可以修复编码或删除Process块内的换行符

function STD-Handler
{  param ($outFile)

    Begin { $null > $outFile }

    Process  {

    $line = "[" + (get-date).Ticks + "]: " + $_ 
     Write-Host $line
     $line >> $outFile

    }

    End  { <# can do smth with the file at the end#>}
}

用法:

python -u C:\ stack \ stdout.py *>&1 | STD处理程序“ C:\ temp \ log.txt”

答案 1 :(得分:0)

部分宾果游戏-其他一些问题涉及PyQt5处理未捕获的异常的方式。不确定PyQt的stderr处理与powershell的stderr处理之间的相互作用,但是,在python中重写sys.excepthook使其具有“旧”行为可以解决问题。这是新的整个r.py python代码-更新后的问题代码的唯一变化是'if name '子句中的'defexception_hook'和'sys.excepthook = except_hook':

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

import sys

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        self.pushButton = QPushButton(Dialog)
        self.pushButton.setObjectName("pushButton")
        self.pushButton.setText(" Add Entry ")
        self.horizontalLayout = QHBoxLayout(Dialog)
        self.horizontalLayout.addWidget(self.pushButton)

class MyWindow(QDialog,Ui_Dialog):
    def __init__(self,parent):
        QDialog.__init__(self)
        self.ui=Ui_Dialog()
        self.ui.setupUi(self)

# click the button to see that stderr inserts line breaks every few
#   characters (different on each occurrance) when openNewEntry is called
#   from the slot/signal flow:      
        self.ui.pushButton.clicked.connect(self.openNewEntry)

# uncomment the following line to see that stderr is line-buffered when
#  openNewEntry is called from code:
#       self.openNewEntry()

    def openNewEntry(self):
        print(1/0)

def except_hook(cls, exception, traceback):
    sys.__excepthook__(cls, exception, traceback)
    exit(-1)

def main():
    app = QApplication(sys.argv)
    w = MyWindow(app)
    w.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    sys.excepthook = except_hook
    main()

现在,单击按钮将产生以下输出:

[636766143015640817]: Traceback (most recent call last):
[636766143015760489]:   File "r.py", line 33, in openNewEntry

[636766143015911442]:
[636766143016031102]: print(1/0)
ZeroDivisionError: division by zero

有时候(不能重复),它在标点符号处有点破裂,但是,这样更易​​于管理:

[636766144719906619]: Traceback (most recent call last):
[636766144720006506]:   File "r.py", line 47, in <module>

[636766144720096055]:
[636766144720195662]: main()
  File "r.py", line 41, in main

[636766144720275744]:
[636766144720375114]: w = MyWindow(app)

[636766144720469728]:   File "r.py", line 30, in __init__

[636766144720565688]:
[636766144720657318]: self.openNewEntry()
  File "r.py", line 33, in openNewEntry

[636766144720757052]:
[636766144720852021]: print(1/0)
ZeroDivisionError
[636766144720946788]: :
[636766144721046802]: division by zero
[636766144721132731]:

这个表现更好的输出也发生在整个程序中(radiolog.py)。

因此,如果有人能进一步阐明为什么仍然发生间歇性局部断裂,那将是很好的,但是,我认为这是一个可行的解决方案。谢谢