기본 콘텐츠로 건너뛰기

추천 가젯

카카오내비 개편, 출근길 정체와 우회 경로를 출발 전에 확인하는 법

카카오내비에서 출근길이 평소보다 얼마나 밀리는지, 막히는 구간을 돌아갈 만한지 출발 전에 판단하기 쉬워집니다. 카카오모빌리티는 11월 11일 카카오내비 홈과 주행 화면을 개편한다고 발표했습니다. 평일 출퇴근길 지연을 홈에 요약하고, 경로를 고르는 단계부터 정체 원인과 CCTV를 보여주는 게 핵심입니다. 영동고속도로와 국도 우회 경로 비교 예시(2012년 자료). 이미지 제공 경기도 G뉴스플러스 . 홈에서 회사·집까지 얼마나 더 걸리는지 확인 홈 상단의 고정 목적지 카드가 평일 아침에는 회사까지, 저녁에는 집까지의 교통 상황을 보여줍니다. 평소보다 예상 소요 시간이 5분 이상 늘어나면 지연 시간과 정체 원인 등을 요약해 표시합니다. 집과 회사를 고정 목적지로 쓰는 운전자라면 출근 전에 카드를 보고 약속 시간에 맞춰 더 일찍 나갈지 판단할 수 있습니다. 빨간 구간의 CCTV를 보고 경로 비교 예전에는 정체 구간에 들어간 뒤에 볼 수 있었던 CCTV 영상, 지연 예상 시간, 정체 원인을 이제 경로 탐색 단계에서도 확인할 수 있습니다. 예를 들어 평소 타는 도로가 사고로 막혔다면, 차를 세워 둔 상태에서 영상과 예상 도착 시간을 보고 기존 경로와 우회 경로를 비교해 보세요. 정체 정보는 주행 중에도 제공되지만 화면을 직접 조작할 때는 안전한 곳에 정차하는 편이 좋습니다. 갈림길 앞에서 차로를 바꿀 시점도 안내 내가 빠질 분기점 앞부터 정체가 이어지면 진출 차로에 미리 들어가도록 권합니다. 바로 앞 분기점만 막히고 내가 빠질 곳은 원활하면, 차로 변경을 조금 뒤로 미루라고 안내할 수 있습니다. 갈림길이 500m 안에 연달아 나오는 구간에서는 도로 이름과 방향을 경로선에 표시하고 통과 순서를 숫자로 보여줍니다. 진출로가 연달아 있는 초행길에서 어느 쪽으로 먼저 빠질지 판단하기 쉬워지는 변화입니다. 내 앱에서 먼저 볼 것 출발 전에 앱 스토어에서 업데이트가 있는지 확인하고, 홈의 고정 목적지 카드와 경로 탐색 화면을 차례로 살펴보세요. 카카오모빌리티 발표...

파이썬 subprocess 완전 정복 ⚙️ — 외부 명령 실행·입출력 캡처·타임아웃

파이썬 subprocess 완전 정복 ⚙️ — 외부 명령 실행·입출력 캡처·타임아웃 subprocess 아이콘

파이썬 subprocess 완전 정복 ⚙️

subprocess는 외부 프로그램 실행을 위한 표준 모듈입니다. 안전한 호출(shell=False), 출력 캡처, 타임아웃, 파이프, 환경/작업폴더 제어까지 운영에 필요한 기능을 모두 제공합니다.

1) 가장 쉬운 방법: subprocess.run

import subprocess

# 리스트 인자 + shell=False (기본) → 안전
result = subprocess.run(
    ["python", "--version"],
    capture_output=True, text=True, check=False
)
print(result.stdout.strip())  # Python 3.x.x
print(result.returncode)
text=True로 자동 디코딩(기본 UTF-8)을 사용하고, 실패 시 예외를 원하면 check=True.

2) 표준출력/표준에러 캡처

import subprocess

res = subprocess.run(
    ["git", "status"],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    text=True
)
print("STDOUT:", res.stdout)
print("STDERR:", res.stderr)

3) 타임아웃과 에러 처리

import subprocess

try:
    subprocess.run(["ping", "-c", "3", "example.com"], timeout=5, check=True)
except subprocess.TimeoutExpired as e:
    print("타임아웃:", e)
except subprocess.CalledProcessError as e:
    print("비정상 종료:", e.returncode, e.stderr)
팁: 타임아웃 시 하위 프로세스가 좀비로 남지 않도록 Popen을 쓰는 경우 proc.kill(); proc.communicate()로 버퍼를 비워 정리하세요.

4) 스트리밍/파이프: Popen

4-1. 실시간 출력 읽기

import subprocess

with subprocess.Popen(
    ["ping", "-c", "3", "example.com"],
    stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1
) as proc:
    for line in proc.stdout:
        print(">>", line.strip())
    code = proc.wait()
print("returncode:", code)

4-2. 두 명령 파이프 연결(UNIX 스타일)

import subprocess

p1 = subprocess.Popen(["ps", "aux"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["grep", "python"], stdin=p1.stdout, stdout=subprocess.PIPE, text=True)
p1.stdout.close()  # 파이프 종단 닫기(좀비 방지)
out, _ = p2.communicate()
print(out)

4-3. 입력을 프로그램에 전달

import subprocess

p = subprocess.Popen(["python", "-c", "print(input()[::-1])"],
                     stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
out, _ = p.communicate("abcde\n")
print(out.strip())  # edcba

5) 환경변수/작업 디렉터리/권한

import os, subprocess

env = dict(os.environ)
env["API_TOKEN"] = "masked"

res = subprocess.run(
    ["python", "script.py"],
    cwd="/path/to/project",   # 작업 디렉터리
    env=env,                  # 환경변수 오버라이드
    capture_output=True, text=True
)
print(res.stdout)

6) Windows & POSIX 차이

  • Windows는 dir, copy 같은 내장은 cmd 전용이므로 shell=True가 필요합니다. 대안: 파워셸 ["powershell","-Command","Get-ChildItem"].
  • 백그라운드/콘솔 창 숨김은 creationflags=subprocess.CREATE_NO_WINDOW (Windows 전용)로 제어.
  • POSIX에서 세션 분리는 preexec_fn=os.setsid 또는 start_new_session=True 사용.

7) 실전 레시피

7-1. JSON 출력 파싱

import subprocess, json

res = subprocess.run(["python","-c",'import json; print(json.dumps({"ok":1}))'],
                     capture_output=True, text=True, check=True)
payload = json.loads(res.stdout)
print(payload["ok"])

7-2. 안전한 사용자 입력 인자화

import subprocess

def grep_safe(pattern, path):
    # 쉘 미사용, 리스트 인자화 → 쉘 인젝션 방지
    return subprocess.run(["grep", "-R", pattern, path],
                          capture_output=True, text=True)

print(grep_safe("TODO", "."))

7-3. 타임아웃 + 강제 종료 정석 패턴

import subprocess

proc = subprocess.Popen(["sleep","10"])
try:
    proc.wait(timeout=3)
except subprocess.TimeoutExpired:
    proc.kill()
    proc.wait()  # 버퍼 비우기/정리

7-4. 대용량 출력 안전 처리(메모리 폭주 방지)

import subprocess

# communicate는 전부 메모리에 적재될 수 있음 → 라인 스트리밍
with subprocess.Popen(["find","/","-maxdepth","1"], stdout=subprocess.PIPE, text=True) as p:
    for line in p.stdout:
        # 라인 단위 처리/저장/전송
        pass

8) 보안 & 베스트 프랙티스

  • shell=False를 기본으로. 정말 필요할 때만 shell=True (그리고 사용자 입력을 절대 그대로 넘기지 않기).
  • 명령·인자는 리스트로 전달. 공백/특수문자 자동 이스케이프.
  • 입력 데이터는 stdin으로 전달하고, 명령 인자에는 로직상 필요한 값만 주입.
  • 타임아웃을 항상 고려하고, 예외 처리로 종료/정리 보장.
  • 로그에 전체 명령행과 시크릿을 그대로 남기지 않기(마스킹).

요약

  • run은 간단 실행/캡처, Popen은 스트리밍·파이프 등 고급 제어.
  • shell=False + 리스트 인자가 보안 기본값.
  • 타임아웃/에러 처리/환경·작업폴더 제어로 운영 신뢰성 확보.

자주 묻는 질문(FAQ)

Q1. UTF-8이 아닌 출력은 어떻게 디코딩하나요?
A. text=True, encoding="cp949" 같이 인코딩을 지정하거나, res.stdout.encode().decode("cp949")로 변환하세요.

Q2. 비동기 병렬 실행은?
A. asyncio.create_subprocess_exec 또는 concurrent.futures.ThreadPoolExecutor로 Popen 호출을 병렬화하세요.

Q3. sudo가 필요한 명령은?
A. 권한 분리 원칙을 우선 적용하고, 필요한 경우에만 최소 범위로 승격하세요. 자동화 시엔 전용 사용자/권한을 분리하는 것이 안전합니다.

댓글

가장 많이 본 글

Icons by Flaticon