Python에서 Bash 명령 실행


299

내 로컬 컴퓨터 에서이 줄을 포함하는 Python 스크립트를 실행합니다.

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
os.system(bashCommand)

이것은 잘 작동합니다.

그런 다음 서버에서 동일한 코드를 실행하면 다음 오류 메시지가 나타납니다.

'import site' failed; use -v for traceback
Traceback (most recent call last):
File "/usr/bin/cwm", line 48, in <module>
from swap import  diag
ImportError: No module named swap

그래서 내가 한 일은 print bashCommand터미널에서 명령보다 인쇄하기 전에 a 를 삽입하는 것입니다 os.system().

물론 오류가 다시 발생 os.system(bashCommand)하지만 (으로 인한 ) 오류가 발생 하기 전에 터미널에서 명령을 인쇄합니다. 그런 다음 방금 출력을 복사하고 터미널에 복사 붙여 넣기를 수행하고 Enter 키를 누르면 작동합니다 ...

누군가 무슨 일이 일어나고 있는지 실마리가 있습니까?


2
실행 방법에 따라 환경에 차이가있는 것 같습니다 cwm. .bashrc대화식 bash 사용을 위해 환경을 설정하는 구성이 있습니까?
Sven Marnach

서버에 로그인 할 때 명령 행에서 명령을 실행하려고 했습니까? 귀하의 게시물은 "터미널에 붙여 넣었습니다"라고 말합니다.
Sven Marnach

@Sven : 예 나는 서버의 터미널에서 직접 명령을 실행했다는 것을 의미했다
mkn

실행 방법에 따라 PYTHONPATH에 차이가있는 것 같습니다 cwm. 또는 PATH에 차이가 있으며 다른 버전 cwm이 호출됩니다. 또는 다른 버전의 Python. 기계에 접근하지 않고는 이것을 이해하기가 정말 어렵습니다 ...
Sven Marnach

답변:


314

를 사용하지 마십시오 os.system. 하위 프로세스 를 위해 더 이상 사용되지 않습니다 . 로부터 문서 : ":이 모듈은 이전의 여러 모듈과 기능을 대체하고자 os.system, os.spawn".

귀하의 경우와 같이 :

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
import subprocess
process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)
output, error = process.communicate()

8
이것은 cd 'path\to\somewhere'어딘가에서 실행 해야하는 또 다른 bash 명령 을 수행해야 할 때 원하는 것을하지 않았습니다 . @ user225312
AWrightIV

36
@AWrightIV 특정 작업 디렉토리에서 하위 프로세스를 실행해야하는 경우 Popen에 cwd인수를 사용할 수 있습니다 .subprocess.Popen(..., cwd='path\to\somewhere')
방수

7
내 명령에는 여기와 같이 shell = True가 필요했습니다. stackoverflow.com/questions/18962785/…
user984003

4
이 경우에는 string.split () 대신 shlex.split ()을 사용하는 것이 좋습니다.
Alexey Sviridov

4
... ( stdout=file이 경우 출력을 파일로 리디렉션합니다. 구현 > file). ..., '>', 'file']리디렉션을 예상하는 마지막 명령 을 전달하는 것은 잘못 될 수 있습니다 (쉘 없이는 작동하지 않으며 쉘을 사용하는 경우 명령을 문자열로 전달해야합니다)
jfs

186

여기의 이전 답변을 다소 확장하기 위해 일반적으로 간과되는 많은 세부 사항이 있습니다.

  • 선호 subprocess.run()이상 subprocess.check_call()에 걸쳐 친구 subprocess.call()이상 subprocess.Popen()이상 os.system()이상os.popen()
  • 아마 text=True일명 이해하고 사용하십시오 universal_newlines=True.
  • 의 의미를 이해 shell=True하거나 shell=False어떻게이 인용 변화와 쉘 편의 시설의 이용 가능성을.
  • shBash 와의 차이점 이해
  • 서브 프로세스가 상위 프로세스와 어떻게 다른지 이해하고 일반적으로 상위 프로세스를 변경할 수 없습니다.
  • Python 인터프리터를 Python의 하위 프로세스로 실행하지 마십시오.

이러한 주제는 아래에보다 자세히 설명되어 있습니다.

선호 subprocess.run()또는subprocess.check_call()

subprocess.Popen()기능은 저급 인력이지만 올바르게 사용하기가 까다 롭고 여러 줄의 코드 복사 / 붙여 넣기를 끝내게됩니다 ... 다양한 목적을 위해 표준 라이브러리에 이미 높은 수준의 래퍼 함수 세트로 이미 존재합니다. 다음에 더 자세히 설명되어 있습니다.

다음은 설명서 의 단락입니다 .

서브 프로세스 호출에 권장되는 접근법 run()은 처리 할 수있는 모든 사용 사례에 대해 기능 을 사용하는 것입니다. 고급 사용 사례의 경우 기본 Popen인터페이스를 직접 사용할 수 있습니다.

불행히도 이러한 래퍼 함수의 가용성은 Python 버전마다 다릅니다.

  • subprocess.run()파이썬 3.5에서 공식적으로 소개되었습니다. 다음을 모두 대체해야합니다.
  • subprocess.check_output()Python 2.7 / 3.1에서 도입되었습니다. 기본적으로subprocess.run(..., check=True, stdout=subprocess.PIPE).stdout
  • subprocess.check_call()파이썬 2.5에서 소개되었습니다. 기본적으로subprocess.run(..., check=True)
  • subprocess.call()Python 2.4에서 원래 subprocess모듈 ( PEP-324 ) 로 도입되었습니다 . 기본적으로subprocess.run(...).returncode

고급 API vs subprocess.Popen()

리팩토링 및 확장 된 subprocess.run()기능은 기존 레거시 기능을 대체하는 것보다 훨씬 논리적이고 다양합니다. CompletedProcess종료 상태, 표준 출력 및 완료된 하위 프로세스에서 몇 가지 다른 결과 및 상태 표시기를 검색 할 수있는 다양한 메소드 가있는 오브젝트를 리턴합니다 .

subprocess.run()파이썬으로 제어를 실행하고 리턴하기 위해 단순히 프로그램이 필요하다면 갈 길입니다. 보다 복잡한 시나리오 (백그라운드 프로세스, Python 상위 프로그램의 대화식 I / O 사용)의 경우 여전히 subprocess.Popen()모든 배관 작업 을 사용 하고 관리 해야합니다 . 이것은 모든 움직이는 부분을 상당히 복잡하게 이해해야하며 가볍게 수행해서는 안됩니다. 더 간단한 Popen객체 는 (아직도 여전히 실행중인) 프로세스를 나타내며이 프로세스는 나머지 하위 프로세스 수명 동안 코드에서 관리해야합니다.

subprocess.Popen()단지 프로세스 만 생성 한다는 점을 강조해야 합니다. 그것을 그대로두면 하위 프로세스가 Python과 함께 실행되므로 "백그라운드"프로세스가됩니다. 입력 또는 출력을 수행하거나 다른 방법으로 조정할 필요가 없으면 Python 프로그램과 함께 유용한 작업을 수행 할 수 있습니다.

os.system()os.popen()

영원한 이후 (파이썬 2.5부터) os모듈 문서 에는 다음 subprocess보다 선호하는 권장 사항이 포함되어 있습니다 os.system().

subprocess모듈은 새로운 프로세스를 생성하고 결과를 검색 할 수있는보다 강력한 기능을 제공합니다. 이 기능을 사용하는 것보다 해당 모듈을 사용하는 것이 좋습니다.

문제 system()는 분명히 시스템에 의존적이며 하위 프로세스와 상호 작용하는 방법을 제공하지 않는다는 것입니다. 파이썬의 범위를 벗어난 표준 출력 및 표준 오류와 함께 간단하게 실행됩니다. 파이썬이 수신하는 유일한 정보는 명령의 종료 상태입니다 (0은 성공을 의미하지만 0이 아닌 값의 의미는 다소 시스템에 따라 다릅니다).

PEP-324 (위에서 이미 언급 한)에는 os.system문제가있는 이유 와 subprocess이러한 문제를 해결하려는 시도에 대한보다 자세한 근거가 포함되어 있습니다.

os.popen()강하게 낙담했었다 :

버전 2.6부터 사용되지 않습니다.이 기능은 더 이상 사용되지 않습니다. subprocess모듈을 사용하십시오 .

그러나 Python 3에서 언젠가는을 사용하기 위해 다시 구현되어 세부 사항 subprocess을 위해 subprocess.Popen()설명서로 리디렉션됩니다 .

이해하고 일반적으로 사용 check=True

또한와 subprocess.call()동일한 제한 사항이 많이 있음 을 알 수 있습니다 os.system(). 정기적으로 사용, 당신은 일반적으로 프로세스가 성공적으로 완료 여부를 확인하는해야 subprocess.check_call()하고 subprocess.check_output()(후자는 완성 된 서브 프로세스의 표준 출력을 반환하는 경우) 할. 마찬가지로 서브 프로세스가 오류 상태를 리턴하도록 특별히 요구하지 않는 한 일반적으로 check=Truewith 를 사용해야 subprocess.run()합니다.

실제로,와 check=Truesubprocess.check_*, 파이썬은 발생합니다 CalledProcessError예외를 하위 프로세스가 제로가 아닌 종료 상태를 반환합니다.

일반적인 오류 는 하위 프로세스가 실패한 경우 다운 스트림 코드가 실패 할 때 subprocess.run()생략 check=True하고 놀라는 것입니다.

반면에, 공통으로 문제 check_call()와는 check_output()경우 예외가 예를 제기 할 때 맹목적으로 이러한 기능을 사용하는 사용자가 놀랐다이었다 grep일치하는 항목을 찾을 수 없습니다. ( grep어쨌든 아래에 설명 된 것처럼 기본 Python 코드로 바꿔야 합니다.)

셀 수있는 모든 것, 쉘 명령이 종료 코드를 리턴하는 방법과 어떤 조건에서 0이 아닌 (오류) 종료 코드를 리턴하는지 이해하고 정확히 처리해야하는 방법을 신중하게 결정해야합니다.

text=True일명 이해하고 아마 사용universal_newlines=True

Python 3부터 Python 내부의 문자열은 유니 코드 문자열입니다. 그러나 서브 프로세스가 유니 코드 출력 또는 문자열을 생성한다는 보장은 없습니다.

(차이가 분명하지 않으면 Ned Batchelder의 Pragmatic Unicode 를 권장합니다. 읽기는 의무적이지 않지만 읽기를 원할 경우 링크 뒤에 36 분짜리 비디오 프레젠테이션이 있지만 페이지를 읽는 데는 시간이 훨씬 적게 걸립니다. )

깊이 내려 가면 파이썬은 bytes버퍼 를 가져와 어떻게 든 해석해야합니다. 이진 데이터가 포함되어 있으면 오류가 발생하기 쉽고 버그를 유발하는 행동이기 때문에 유니 코드 문자열로 디코딩 해서는 안됩니다 . 인코딩 된 텍스트와 이진 데이터를 올바르게 구분합니다.

을 사용하면 text=True실제로 시스템의 기본 인코딩에서 텍스트 데이터를 다시 기대할 수 있으며 Python의 능력을 최대한 발휘할 수 있도록 Python (유니 코드) 문자열로 디코딩해야합니다. 아마도 Windows를 제외한 날짜 시스템?)

그것이 다시 요청 하지 않으면 파이썬은 bytes문자열 stdoutstderr문자열을 제공합니다. 어쩌면 일부에서 나중에 지적 그들이 텍스트 문자열이 결국 있다고 알고, 당신은 자신의 인코딩을 알고있다. 그런 다음 해독 할 수 있습니다.

normal = subprocess.run([external, arg],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    check=True,
    text=True)
print(normal.stdout)

convoluted = subprocess.run([external, arg],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    check=True)
# You have to know (or guess) the encoding
print(convoluted.stdout.decode('utf-8'))

Python 3.7 text은 이전에 다소 오도 된 키워드 인수에 대해 더 짧고 이해하기 쉽고 이해하기 쉬운 별명 을 도입했습니다 universal_newlines.

이해 shell=Trueshell=False

함께 shell=True하면 쉘에 하나의 문자열을 전달하고, 쉘은 거기에서 걸립니다.

함께 shell=False하면 쉘을 우회 OS에 인수 목록을 전달합니다.

쉘이없는 경우 프로세스를 저장하고 상당히 많은 양의 숨겨진 복잡성을 제거하여 버그 나 보안 문제가있을 수 있습니다.

반면에 쉘이없는 경우 리디렉션, 와일드 카드 확장, 작업 제어 및 기타 여러 가지 쉘 기능이 없습니다.

일반적인 실수는 shell=True파이썬 을 사용 하여 토큰 목록을 전달하는 것입니다. 이것은 어떤 경우에는 효과가 있지만 실제로는 잘못 정의되어 있으며 흥미로운 방식으로 깨질 수 있습니다.

# XXX AVOID THIS BUG
buggy = subprocess.run('dig +short stackoverflow.com')

# XXX AVOID THIS BUG TOO
broken = subprocess.run(['dig', '+short', 'stackoverflow.com'],
    shell=True)

# XXX DEFINITELY AVOID THIS
pathological = subprocess.run(['dig +short stackoverflow.com'],
    shell=True)

correct = subprocess.run(['dig', '+short', 'stackoverflow.com'],
    # Probably don't forget these, too
    check=True, text=True)

# XXX Probably better avoid shell=True
# but this is nominally correct
fixed_but_fugly = subprocess.run('dig +short stackoverflow.com',
    shell=True,
    # Probably don't forget these, too
    check=True, text=True)

일반적인 레토르트 "하지만 그것은 나를 위해 작동합니다"는 당신이 그것이 어떤 상황에서 작동을 멈출 수 있는지 정확히 이해하지 않는 한 유용한 반박이 아닙니다.

리팩토링 예제

종종 쉘의 기능을 원시 파이썬 코드로 대체 할 수 있습니다. Simple Awk 또는 sed스크립트는 아마도 단순히 Python으로 변환되어야합니다.

이것을 부분적으로 설명하기 위해 많은 쉘 기능을 포함하는 일반적이지만 약간 어리석은 예가 있습니다.

cmd = '''while read -r x;
   do ping -c 3 "$x" | grep 'round-trip min/avg/max'
   done <hosts.txt'''

# Trivial but horrible
results = subprocess.run(
    cmd, shell=True, universal_newlines=True, check=True)
print(results.stdout)

# Reimplement with shell=False
with open('hosts.txt') as hosts:
    for host in hosts:
        host = host.rstrip('\n')  # drop newline
        ping = subprocess.run(
             ['ping', '-c', '3', host],
             text=True,
             stdout=subprocess.PIPE,
             check=True)
        for line in ping.stdout.split('\n'):
             if 'round-trip min/avg/max' in line:
                 print('{}: {}'.format(host, line))

여기에 참고할 사항 :

  • shell=False쉘이 문자열을 주변에 요구하는 당신에게 인용을 필요로하지 않습니다. 어쨌든 따옴표를 넣는 것은 아마도 오류 일 것입니다.
  • 하위 프로세스에서 가능한 한 적은 코드를 실행하는 것이 좋습니다. 이를 통해 Python 코드 내에서 실행을보다 효과적으로 제어 할 수 있습니다.
  • 그러나 복잡한 쉘 파이프 라인은 지루하고 때로는 파이썬에서 다시 구현하기가 어렵습니다.

리팩토링 된 코드는 셸이 매우 간결한 구문을 사용하여 실제로 얼마나 많은 일을하는지 보여줍니다. 파이썬은 명시 적이 암시 적보다 낫다고 말하지만 파이썬 코드 다소 장황하며 실제로 이것보다 더 복잡해 보입니다. 반면에 쉘 명령 출력과 함께 호스트 이름을 쉽게 포함시킬 수있는 기능 향상으로 사소한 부분을 제어 할 수있는 여러 지점을 제공합니다. (이것은 쉘에서 수행하는 데 결코 도전이 아니며, 또 다른 전환과 다른 프로세스를 희생하여 발생합니다.)

일반적인 쉘 구조

완전성을 위해 다음은 이러한 쉘 기능 중 일부에 대한 간략한 설명과 기본 Python 기능으로 대체 할 수있는 방법에 대한 참고 사항입니다.

  • 글 로빙 일명 와일드 카드 확장은와 glob.glob()같은 간단한 파이썬 문자열 비교 로 대체 하거나 대체 할 수 있습니다 for file in os.listdir('.'): if not file.endswith('.png'): continue. Bash에는 .{png,jpg}괄호 확장 및 {1..100}물결표 확장과 같은 다양한 기타 확장 기능 ~이 있습니다 (홈 디렉토리로, 더 일반적으로 ~account는 다른 사용자의 홈 디렉토리로 확장 )
  • 쉘 변수 는 파이썬 변수와 유사 $SHELL하거나 $my_exported_var때로는 간단하게 대체 될 수 있습니다. 예를 들어 같은 수출 쉘 변수를 사용할 수 있습니다 os.environ['SHELL'](의 의미가 export하위 프로세스에 변수를 사용할 수 있도록하는 것입니다 -. 분명히 파이썬은 쉘의 서브 프로세스, 또는 반대의 부사장으로 실행에 사용할 수 없습니다 서브 프로세스에 사용할 수없는 변수 env=키워드 subprocess메소드에 대한 인수를 사용하면 서브 프로세스의 환경을 사전으로 정의 할 수 있으므로 서브 프로세스에 Python 변수를 표시 할 수 있습니다. 함께 shell=False하면 어떤 따옴표를 제거하는 방법을 이해해야합니다; 예를 들어, 디렉토리 이름을 따옴표없이 사용 cd "$HOME"하는 것과 같습니다 os.chdir(os.environ['HOME']). (매우 자주cd어쨌든 유용하거나 필요하지 않으며 많은 초보자는 변수 주위에 큰 따옴표를 생략하고 하루까지 그 단어를 사용하지 않습니다 ... )
  • 리디렉션을 사용하면 파일에서 표준 입력으로 읽고 표준 출력을 파일에 쓸 수 있습니다. 쓰기 및 읽기를 위해 grep 'foo' <inputfile >outputfile열리고 해당 내용을 표준 입력으로 전달합니다 . 표준 출력은에 입력됩니다 . 일반적으로 네이티브 Python 코드로 대체하기는 어렵지 않습니다.outputfileinputfilegrepoutputfile
  • 파이프 라인은 일종의 리디렉션입니다. echo foo | nl두 개의 하위 프로세스를 실행합니다. 여기서 표준 출력은 echo표준 입력입니다 nl(OS 수준에서 Unix 계열 시스템에서는 단일 파일 핸들 임). 파이프 라인의 한쪽 끝이나 양쪽 끝을 네이티브 파이썬 코드로 대체 할 수없는 경우, 특히 파이프 라인에 2-3 개 이상의 프로세스가 pipes있는 경우 (파이썬 표준 라이브러리모듈 이나 숫자를 보더라도) 쉘 사용을 고려하십시오. 보다 현대적이고 다양한 타사 경쟁 업체).
  • 작업 제어를 통해 작업을 중단하고 백그라운드에서 실행하고 포 그라운드로 되돌릴 수 있습니다. 프로세스를 중지하고 계속하기위한 기본 Unix 신호도 물론 Python에서도 사용할 수 있습니다. 그러나 작업은 쉘에서 상위 레벨 추상화로, 프로세스 그룹 등이 포함됩니다. 파이썬에서 이와 같은 작업을 수행하려면 이해해야합니다.
  • 쉘에서 인용하는 것은 모든 것이 기본적으로 문자열 이라는 것을 이해할 때까지 혼란 스러울 수 있습니다 . 그래서 ls -l /에 해당 'ls' '-l' '/'하지만, 주위에 인용 리터럴은 완전히 선택 사항입니다. 쉘 메타 문자를 포함하는 따옴표없는 문자열에는 매개 변수 확장, 공백 토큰 화 및 와일드 카드 확장이 적용됩니다. 큰 따옴표는 공백 토큰 화 및 와일드 카드 확장을 방지하지만 매개 변수 확장 (변수 대체, 명령 대체 및 백 슬래시 처리)을 허용합니다. 이론 상으로는 간단하지만 특히 여러 계층의 해석 (예 : 원격 셸 명령)이있는 경우 당황 할 수 있습니다.

shBash 와의 차이점 이해

subprocess/bin/sh특별히 다르게 요청하지 않는 한 쉘 명령을 실행합니다 (물론 Windows에서 COMSPEC변수 값을 사용하는 경우는 제외 ). 것을이 수단 다양한 배쉬 전용 배열 같은 기능, [[등은 사용할 수 없습니다.

Bash 전용 구문을 사용해야하는 경우 셸 경로를 다음과 같이 전달할 수 있습니다 executable='/bin/bash'(물론 Bash가 다른 곳에 설치된 경우 경로를 조정해야합니다).

subprocess.run('''
    # This for loop syntax is Bash only
    for((i=1;i<=$#;i++)); do
        # Arrays are Bash-only
        array[i]+=123
    done''',
    shell=True, check=True,
    executable='/bin/bash')

A subprocess는 부모와 분리되어 있으며 변경할 수 없습니다

다소 일반적인 실수는 다음과 같은 일을하는 것입니다.

subprocess.run('foo=bar', shell=True)
subprocess.run('echo "$foo"', shell=True)  # Doesn't work

우아함의 부족을 제외하고는 "서브 프로세스"라는 이름의 "서브"부분에 대한 이해의 근본적인 부족을 배신한다.

자식 프로세스는 파이썬과 완전히 별개로 실행되며, 끝날 때 파이썬은 종료 상태에서 유추하여 자식 프로세스의 출력을 유추 할 수있는 모호한 표시기 외에는 무엇을했는지 전혀 모릅니다. 아이는 일반적으로 부모의 환경을 바꿀 수 없습니다. 변수를 설정하거나 작업 디렉토리를 변경하거나 많은 경우 부모의 협조없이 부모와 통신 할 수 없습니다.

이 특정한 경우의 즉각적인 수정은 단일 하위 프로세스에서 두 명령을 모두 실행하는 것입니다.

subprocess.run('foo=bar; echo "$foo"', shell=True)

분명히이 특별한 유스 케이스에는 쉘이 전혀 필요하지 않습니다. 다음을 통해 현재 프로세스 (및 그 자식)의 환경을 조작 할 수 있습니다.

os.environ['foo'] = 'bar'

또는 환경 설정을 사용하여 하위 프로세스에 환경 설정을 전달하십시오.

subprocess.run('echo "$foo"', shell=True, env={'foo': 'bar'})

(명백한 리팩토링을 언급하지 않기 위하여 subprocess.run(['echo', 'bar']),하지만 echo실행에 무언가의 빈약 한 예는 물론, 처음부터 하위 프로세스에있다).

파이썬에서 파이썬을 실행하지 마십시오

이것은 약간 모호한 조언입니다. 파이썬 인터프리터를 파이썬 스크립트의 서브 프로세스로 실행해야하는 상황이 있거나 심지어는 절대적으로 필요한 상황도 있습니다. 그러나 종종 올바른 접근 방식은 단순히 import다른 파이썬 모듈이 호출 스크립트에 들어가 함수를 직접 호출하는 것입니다.

다른 파이썬 스크립트가 당신의 통제하에 있고 그것이 모듈이 아닌 경우, 하나로 바꾸는 것을 고려 하십시오 . (이 답변은 이미 너무 길기 때문에 여기서 자세히 다루지 않겠습니다.)

병렬 처리가 필요한 경우 multiprocessing모듈을 사용하여 하위 프로세스에서 Python 함수를 실행할 수 있습니다 . threading단일 프로세스에서 여러 작업을 실행하는 작업 도 있습니다 (더 가볍고 더 많은 제어 기능을 제공하지만 프로세스 내의 스레드가 밀접하게 결합되어 단일 GIL에 바인딩되어 있음 ).


2
파이썬을 하위 프로세스로 호출하지 않는 방법에 대한 자세한 설명은 접선 적으로 비슷한 질문에 대한이 답변을
tripleee

4
관용적으로 질문에서 명령을 실행하는 방법을 보여주기 위해 그러한 기본 질문에 대한 새로운 답변을 게시해야한다는 생각이 들었습니다. 당신의 대답은 길지만 그런 예를 보지 못합니다. 무관 :화물 배양을 피하십시오. 귀하의 경우 check_call ()이 작동하면 사용하십시오. run()맹목적으로 사용되는 코드를 수정해야했습니다 . 누락 된 check=True버그는 check_call이 사용 된 경우 피할 수있는 버그를 일으켰습니다. "check"가 이름에 있으면 잃어 버릴 수 없습니다. 올바른 기본값입니다. 오류를 자동으로 무시하지 마십시오. 나는 더 이상 읽지 않았다.
jfs

1
@jfs 의견을 보내 주셔서 감사합니다. 사실 Bash와 관련하여 섹션을 추가 할 계획 sh이었지만 당신은 저를 이겼습니다. 나는 이러한 함정이 분명하지 않은 초보자에게 도움이 될 정도로 세부 사항을 자세하게 설명하려고 노력하고 있습니다. 그렇지 않으면 귀하의 것으로 충분합니다. +1
tripleee

않습니다 stderr/stdout = subprocess.PIPE기본 설정보다 높은 성능 오버 헤드가?
Stringers

1
@Stringers 테스트하지 않았지만 그 이유를 모르겠습니다. 그 파이프를 어떤 처리를하는 것에 연결한다면, 그 처리는 계산되어야합니다. 그러나 파이프 자체에서는 발생하지 않습니다. 기본값은 stdout 또는 stderr을 전혀 캡처하지 않는 것입니다. 즉, 인쇄 된 모든 것이 파이썬의 가시성 및 제어에서와 같이 os.system().
tripleee

41

하위 프로세스로 호출

import subprocess
subprocess.Popen("cwm --rdf test.rdf --ntriples > test.nt")

서버에 스왑 모듈이 없기 때문에 오류가 발생하는 것 같습니다. 서버에 스왑을 설치 한 다음 스크립트를 다시 실행해야합니다


3
swap쉘 작품에서 명령을 실행하기 때문에 모듈은 분명히있다.
Sven Marnach

2
서버가 아닌 서버에서 서버를 실행할 때 가져 오기 오류가 있습니다.
Jakob Bowyer

@mkn : "그런 다음 출력을 복사해서 터미널에 복사 붙여 넣기를해서 Enter 키를 누르면 작동합니다 ..."-서버 나 컴퓨터에서 시도 했습니까?
Sven Marnach

독립형 컴퓨터에서 이것을 실행하고 있지만 서버에서 실행할 때 작동하지 않습니까? 또는 서버 자체에서는 서버 터미널에서 실행할 수
없습니까?

1
그것이 잘못된 사용하지 않는 경우 shell=True다음 여러 인자, 즉 전달하는 목록을 사용한다, 사용 ['a', 'b', 'c']대신에 'a b c'. > file명령의 (쉘 리디렉션) 으로 인해 순진 분할이 작동하지 않지만 . 자세한 내용
jfs

18

명령을 실행하기 위해 매개 변수 -c와 함께 bash 프로그램을 사용할 수 있습니다.

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
output = subprocess.check_output(['bash','-c', bashCommand])

2
subprocess.check_output(bashCommand, shell=True)같은 일을합니다. 명령이 정적 문자열 인 경우 직접 목록으로 구문 분석하고 shell=True; with open('test.nt', 'w') as dest: output = subprocess.check_output(['cwm' ,'--rdf', 'test.rdf', '--ntriples'], stdout=dest, shell=False)
그러나이

@tripleee 참고 : /bin/sh(서브 프로세스에 의해 사용되는) 것은 반드시 필요한 것은 아닙니다 ( bashism을 bash사용할 수는 없습니다). executable='/bin/bash원하는 경우 사용할 수 있습니다 . 다음은 코드 예제입니다
jfs

2
명령이 성공적으로 시작되어야하는 첫 번째 답입니다 (허용되고 두 번째로 인기있는 답은 잘못되었습니다. 사소한 떨림 : check_output()여기서는 쓸모가 없습니다 ( > file리디렉션 으로 인해 출력이 항상 비어 있음 ; 사용)check_call() . 대신 사용하십시오)
jfs

16

을 사용할 수는 subprocess있지만 항상 'Pythonic'방식이 아니라고 생각했습니다. 따라서 명령 줄 기능을 쉽게 실행할 수있는 Sultan (shameless plug)을 만들었습니다.

https://github.com/aeroxis/sultan


3
잘 했어! 하위 프로세스보다 훨씬 깨끗하고 직관적입니다.
mjd2

정말 고맙습니다! 기뻐요!
David Daniel

2
이것은 표준 라이브러리에 정직하게 적용되어야합니다.
Joshua Detwiler

1
Sultan을 사용하여 터미널의 출력을 캡처하는 방법이 있습니까?
alvas

네 당신은 @alvas 수 있습니다 ... 여기에 그것을 수행하는 방법에 대한 문서가 있습니다 : sultan.readthedocs.io/en/latest/…
David Daniel

7

오류에 따르면 서버에 swap 이라는 패키지가 없습니다 . 이것이 /usr/bin/cwm필요합니다. Ubuntu / Debian을 사용 python-swap하는 경우 aptitude를 사용하여 설치하십시오 .


하지만 터미널에서 직접 실행할 때 작동하므로 스왑이 있어야합니까?
mkn

두 가지 옵션이 있습니다. 찾을 수 swap없거나 처음에 가져 오지 않아야합니다. import swap수동으로 할 수 있습니까? 작동합니까?
kichik

흠. 터미널에 python을 입력하여 파이썬을 시작한 다음 import swap을 입력하면 "ImportError : No module named swap"이라는 오류가 발생합니다. 이상한 점은 여전히 ​​서버의 터미널에서 cwm 명령을 실행할 때 작동한다는 것입니다.
mkn

sys.path작동하는 곳과 그렇지 않은 곳에서 인쇄 해보십시오 . 그런 다음 인쇄 된 폴더에서 swap 폴더 또는 swap.py를 찾으십시오. 스벤이 말했듯이, 그 길에 문제가있을 수 있으며, 이것은 당신이 그것을 이해하는 데 도움이 될 것입니다.
kichik

4

또한 'os.popen'을 사용할 수 있습니다. 예:

import os

command = os.popen('ls -al')
print(command.read())
print(command.close())

산출:

total 16
drwxr-xr-x 2 root root 4096 ago 13 21:53 .
drwxr-xr-x 4 root root 4096 ago 13 01:50 ..
-rw-r--r-- 1 root root 1278 ago 13 21:12 bot.py
-rw-r--r-- 1 root root   77 ago 13 21:53 test.py

None

1
설명서 에는 큰 빨간색 상자가 포함되어 있습니다. " 버전 2.6 이후 사용되지 않음 : 이 기능은 더 이상 사용되지 않습니다. subprocess모듈을 사용하십시오 ."
tripleee

1
공평하게, os.popen더 이상이 경고가 없으며, 이제는 단순히 얇은 포장지 subprocess.Popen()입니다.
tripleee

4

쉘없이 명령을 실행하려면 명령을 목록 으로 전달하고 [subprocess]다음을 사용하여 Python에서 리디렉션을 구현하십시오 .

#!/usr/bin/env python
import subprocess

with open('test.nt', 'wb', 0) as file:
    subprocess.check_call("cwm --rdf test.rdf --ntriples".split(),
                          stdout=file)

참고 : > test.nt마지막 에는 없습니다 . stdout=file리디렉션을 구현합니다.


파이썬에서 쉘을 사용하여 명령을 실행하려면 명령을 문자열 로 전달 하고 활성화하십시오 shell=True.

#!/usr/bin/env python
import subprocess

subprocess.check_call("cwm --rdf test.rdf --ntriples > test.nt",
                      shell=True)

다음은 셸이 출력 리디렉션을 담당합니다 ( > test.nt명령에 있음).


사용의 bashisms이,에, 명시 적으로 예를 들어, bash는 실행 파일을 지정하는 bash는 명령을 실행하려면 에뮬레이션 bash는 프로세스 대체 :

#!/usr/bin/env python
import subprocess

subprocess.check_call('program <(command) <(another-command)',
                      shell=True, executable='/bin/bash')

아마도 .split()인용 된 문자열 등이있을 때 적절하지 않다고 언급 할 수 있습니다 shlex.split(). 임의로 복잡한 쉘 구문에 대응 하는 별도의 루틴 이 있습니다.
tripleee

.split()이 경우 @tripleee 작품. shlex.split()때로는 유용 할 수 있지만 일부 경우에는 실패 할 수도 있습니다. 언급 할 수있는 많은 것들이 있습니다. 위에서 제공된 서브 프로세스 태그 설명에 대한 링크로 시작할 수 있습니다.
jfs

0

이 작업을 수행하는 pythonic 방법은 subprocess.Popen

subprocess.Popen 첫 번째 요소가 실행될 명령과 명령 행 인수가있는 목록을 가져옵니다.

예로서:

import subprocess

args = ['echo', 'Hello!']
subprocess.Popen(args) // same as running `echo Hello!` on cmd line

args2 = ['echo', '-v', '"Hello Again"']
subprocess.Popen(args2) // same as running 'echo -v "Hello Again!"` on cmd line

아니요, 마지막 예는 echo -v '"Hello Again!"'큰 따옴표를 작은 따옴표 로 실행하는 것과 같습니다 .
tripleee

또한를 올바르게 사용 subprocesss.Popen하려면 결과 프로세스 객체를 관리해야합니다 (최소한, wait()좀비 프로세스로 전환되지 않도록 a 수행 ).
tripleee
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.