[PYTHON] 파이썬에서 stdout에 C 공유 라이브러리가 인쇄되지 않게하려면 어떻게해야합니까?
PYTHON파이썬에서 stdout에 C 공유 라이브러리가 인쇄되지 않게하려면 어떻게해야합니까?
내가 stdout에 인쇄 C 공유 라이브러리를 가져 오는 파이썬 lib와 함께 작동합니다. 파이프와 함께 사용하거나 파일을 리디렉션하기 위해 깨끗한 출력을 원합니다. 인쇄물은 파이썬 외부, 공유 라이브러리에서 처리됩니다.
처음에는 다음과 같은 접근 방식이 사용되었습니다.
# file: test.py
import os
from ctypes import *
from tempfile import mktemp
libc = CDLL("libc.so.6")
print # That's here on purpose, otherwise hello word is always printed
tempfile = open(mktemp(),'w')
savestdout = os.dup(1)
os.close(1)
if os.dup(tempfile.fileno()) != 1:
assert False, "couldn't redirect stdout - dup() error"
# let's pretend this is a call to my library
libc.printf("hello world\n")
os.close(1)
os.dup(savestdout)
os.close(savestdout)
이 첫 번째 접근법은 절반의 작업입니다. - 어떤 이유로 stdout을 옮기기 바로 전에 "print"문이 필요합니다. 그렇지 않으면 hello word가 항상 출력됩니다. 결과적으로 라이브러리가 일반적으로 출력하는 모서리 대신 빈 줄이 인쇄됩니다. - 더 성가신, 그것은 파일로 리디렉션 할 때 실패 :
$python test.py > foo && cat foo
hello world
내 두 번째 파이썬 시도는 주석에 제공된 다른 유사한 스레드에서 영감을 얻었다.
import os
import sys
from ctypes import *
libc = CDLL("libc.so.6")
devnull = open('/dev/null', 'w')
oldstdout = os.dup(sys.stdout.fileno())
os.dup2(devnull.fileno(), 1)
# We still pretend this is a call to my library
libc.printf("hello\n")
os.dup2(oldstdout, 1)
이 또한 "안녕하세요"가 인쇄하지 못하게합니다.
이것이 조금 낮은 수준이라고 느꼈으므로, 나는 ctypes로 완전히 가기로 결정했습니다. 나는 아무것도 인쇄하지 않는이 C 프로그램에서 영감을 얻었다.
#include <stdio.h>
int main(int argc, const char *argv[]) {
char buf[20];
int saved_stdout = dup(1);
freopen("/dev/null", "w", stdout);
printf("hello\n"); // not printed
sprintf(buf, "/dev/fd/%d", saved_stdout);
freopen(buf, "w", stdout);
return 0;
}
다음 예제를 만들었습니다.
from ctypes import *
libc = CDLL("libc.so.6")
saved_stdout = libc.dup(1)
stdout = libc.fdopen(1, "w")
libc.freopen("/dev/null", "w", stdout);
libc.printf("hello\n")
libc.freopen("/dev/fd/" + str(saved_stdout), "w", stdout)
이것은 printf 바로 뒤에 libc.fflush (stdout)가 있더라도 "hello"를 출력합니다. 파이썬에서 원하는 것을 할 수 없다고 생각하기 시작했습니다. 아니면 stdout에 파일 포인터를 얻는 방법이 옳지 않다.
어떻게 생각해?
해결법
-
==============================
1.@Yinon Ehrlich의 대답을 기반으로합니다. 이 변종은 파일 기술자 유출을 피하려고합니다 :
@Yinon Ehrlich의 대답을 기반으로합니다. 이 변종은 파일 기술자 유출을 피하려고합니다 :
import os import sys from contextlib import contextmanager @contextmanager def stdout_redirected(to=os.devnull): ''' import os with stdout_redirected(to=filename): print("from Python") os.system("echo non-Python applications are also supported") ''' fd = sys.stdout.fileno() ##### assert that Python and C stdio write using the same file descriptor ####assert libc.fileno(ctypes.c_void_p.in_dll(libc, "stdout")) == fd == 1 def _redirect_stdout(to): sys.stdout.close() # + implicit flush() os.dup2(to.fileno(), fd) # fd writes to 'to' file sys.stdout = os.fdopen(fd, 'w') # Python writes to fd with os.fdopen(os.dup(fd), 'w') as old_stdout: with open(to, 'w') as file: _redirect_stdout(to=file) try: yield # allow code to be run with the redirected stdout finally: _redirect_stdout(to=old_stdout) # restore stdout. # buffering and flags such as # CLOEXEC may be different
-
==============================
2.예, 두 번째 아이디어처럼 os.dup 대신 os.dup2를 사용하고 싶습니다. 코드가 다소 우연히 보입니다. / dev / null을 제외하고는 / dev 항목을 쓰지 마십시오. 불필요합니다. 여기 C에서 아무것도 쓰지 않아도됩니다.
예, 두 번째 아이디어처럼 os.dup 대신 os.dup2를 사용하고 싶습니다. 코드가 다소 우연히 보입니다. / dev / null을 제외하고는 / dev 항목을 쓰지 마십시오. 불필요합니다. 여기 C에서 아무것도 쓰지 않아도됩니다.
트릭은 dup을 사용하여 stdout fdes를 저장 한 다음 fdopen에 전달하여 새로운 sys.stdout Python 객체를 작성하는 것입니다. 한편 fdes를 / dev / null로 열고 dup2를 사용하여 기존 stdout fdes를 덮어 씁니다. 그런 다음 이전 fdes를 / dev / null로 닫습니다. dup2를 호출하는 것이 필요합니다. 왜냐하면 어떤 fdes를 반환 할지를 알 수 없기 때문에 dup2가이를 수행하는 유일한 방법입니다.
편집 : 그리고 당신이 파일로 리디렉션하는 경우, stdout 라인 버퍼되지 않습니다, 그래서 당신은 그것을 플러시해야합니다. 파이썬에서 그렇게 할 수 있으며, C와 정확하게 상호 운용됩니다. 물론 stdout에 아무 것도 쓰지 않기 전에이 함수를 호출하면 문제가되지 않습니다.
다음은 방금 테스트 한 예제입니다.
import zook import os import sys def redirect_stdout(): print "Redirecting stdout" sys.stdout.flush() # <--- important when redirecting to files newstdout = os.dup(1) devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, 1) os.close(devnull) sys.stdout = os.fdopen(newstdout, 'w') zook.myfunc() redirect_stdout() zook.myfunc() print "But python can still print to stdout..."
"zook"모듈은 C에서 매우 간단한 라이브러리입니다.
#include <Python.h> #include <stdio.h> static PyObject * myfunc(PyObject *self, PyObject *args) { puts("myfunc called"); Py_INCREF(Py_None); return Py_None; } static PyMethodDef zookMethods[] = { {"myfunc", myfunc, METH_VARARGS, "Print a string."}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC initzook(void) { (void)Py_InitModule("zook", zookMethods); }
출력은?
$ python2.5 test.py myfunc called Redirecting stdout But python can still print to stdout...
파일로 리디렉션합니까?
$ python2.5 test.py > test.txt $ cat test.txt myfunc called Redirecting stdout But python can still print to stdout...
-
==============================
3.컨텍스트 관리자에게 두 답변을 결합하여 해당 범위에 대해 stdout으로 인쇄를 차단하는 컨텍스트 관리자 (첫 번째 대답의 코드 외부 출력을 차단했는데, 후자의 대답은 sys.stdout.flush ()를 마지막에 놓쳤습니다.
컨텍스트 관리자에게 두 답변을 결합하여 해당 범위에 대해 stdout으로 인쇄를 차단하는 컨텍스트 관리자 (첫 번째 대답의 코드 외부 출력을 차단했는데, 후자의 대답은 sys.stdout.flush ()를 마지막에 놓쳤습니다.
class HideOutput(object): ''' A context manager that block stdout for its scope, usage: with HideOutput(): os.system('ls -l') ''' def __init__(self, *args, **kw): sys.stdout.flush() self._origstdout = sys.stdout self._oldstdout_fno = os.dup(sys.stdout.fileno()) self._devnull = os.open(os.devnull, os.O_WRONLY) def __enter__(self): self._newstdout = os.dup(1) os.dup2(self._devnull, 1) os.close(self._devnull) sys.stdout = os.fdopen(self._newstdout, 'w') def __exit__(self, exc_type, exc_val, exc_tb): sys.stdout = self._origstdout sys.stdout.flush() os.dup2(self._oldstdout_fno, 1)
-
==============================
4.내가 마침내 한 일이 여기있다. 나는 이것이 다른 사람들에게 유용 할 수 있기를 바란다. (이것은 나의 리눅스 스테이션에서 작동한다.)
내가 마침내 한 일이 여기있다. 나는 이것이 다른 사람들에게 유용 할 수 있기를 바란다. (이것은 나의 리눅스 스테이션에서 작동한다.)
나는 자랑스럽게 외부 라이브러리를 닥치기 위해 고안된 libshutup을 제시한다.
1) 다음 파일을 복사하십시오.
// file: shutup.c #include <stdio.h> #include <unistd.h> static char buf[20]; static int saved_stdout; void stdout_off() { saved_stdout = dup(1); freopen("/dev/null", "w", stdout); } void stdout_on() { sprintf(buf, "/dev/fd/%d", saved_stdout); freopen(buf, "w", stdout); }
2) 공유 라이브러리로 컴파일
gcc -Wall -shared shutup.c -fPIC -o libshutup.so
3) 이것을 다음과 같이 코드에서 사용하십시오.
from ctypes import * shutup = CDLL("libshutup.so") shutup.stdout_off() # Let's pretend this printf comes from the external lib libc = CDLL("libc.so.6") libc.printf("hello\n") shutup.stdout_on()
-
==============================
5.파이썬에서 할 때와 똑같이 할 수 없습니까? sys를 가져오고 sys.stdout 및 sys.stderr을 기본 sys.stdout 및 sys.stderr가 아닌 다른 것으로 지정합니다. 나는 라이브러리에서 출력을 버려야하는 몇 가지 응용 프로그램에서 항상이 작업을 수행합니다.
파이썬에서 할 때와 똑같이 할 수 없습니까? sys를 가져오고 sys.stdout 및 sys.stderr을 기본 sys.stdout 및 sys.stderr가 아닌 다른 것으로 지정합니다. 나는 라이브러리에서 출력을 버려야하는 몇 가지 응용 프로그램에서 항상이 작업을 수행합니다.
from https://stackoverflow.com/questions/5081657/how-do-i-prevent-a-c-shared-library-to-print-on-stdout-in-python by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] 파일의 텍스트를 파이썬으로 대체하기 (0) | 2018.10.11 |
---|---|
[PYTHON] 파이썬 2.7의 문자열에서 유니 코드 \ u2026을 제거하는 중 (0) | 2018.10.11 |
[PYTHON] 파이썬을 통해 연결할 때 기본 Mysql 연결 시간 초과를 어떻게 바꿀 수 있습니까? (0) | 2018.10.11 |
[PYTHON] 사전에 매핑 된 값이있는 새 팬더 열 추가 (0) | 2018.10.11 |
[PYTHON] 파이썬에서 "global"문을 사용합니까? [닫은] (0) | 2018.10.11 |