윈도우 파이썬 os.execv 재시작이 띄어쓰기 경로에서 죽을 때

결론부터
증상: 스스로 새 판을 받고 os.execv 로 다시 뜨게 만든 파이썬 프로그램이 재시작 뒤 흔적 없이 사라집니다.
원인: 윈도우 파이썬의 os.execv 는 인자를 이을 때 따옴표를 붙이지 않아, 띄어쓰기가 든 경로가 잘린 채 넘어갑니다.
해결: subprocess.Popen 에 인자를 목록으로 넘겨 새 프로세스를 띄우고 os._exit(0) 으로 끝냅니다.

리눅스에서 잘 쓰던 자기 재시작 코드를 윈도우에 그대로 가져가면 조용히 실패할 수 있습니다. 특히 프로그램 폴더 이름에 띄어쓰기가 있을 때입니다. 실제로 백그라운드로 도는 파이썬 작업 하나가 이 때문에 멈췄습니다.

업데이트 뒤 프로그램이 사라졌다

이 프로그램은 서버에서 새 판을 받으면 파일을 바꾸고 os.execv 로 자기 자신을 다시 띄우게 되어 있었습니다. 그런데 어느 업데이트 뒤로 프로그램이 다시 뜨지 않았습니다.

pythonw 로 창 없이 돌던 프로그램이라 오류 창도, 로그도 남지 않았습니다. 겉으로 보인 증거는 서버 쪽에서 3분마다 오던 접속이 끊겼다는 것 하나뿐이었습니다.

execv 가 경로를 따옴표로 감싸지 않는다

윈도우에는 리눅스의 exec 같은 "현재 프로세스를 바꿔 끼우는" 동작이 따로 없어서, 파이썬은 인자 목록을 한 줄의 명령줄로 이어 새 프로세스를 만듭니다. 이때 윈도우 파이썬의 os.execv 는 각 인자를 따옴표로 감싸지 않습니다.

그래서 C:\My Tools\worker\run.py 같은 경로는 새 프로세스에서 C:\My 와 Tools\worker\run.py 두 인자로 갈라집니다. 파이썬은 C:\My 라는 스크립트를 찾지 못하고 바로 끝납니다. 창이 없으니 그 오류를 볼 사람도 없습니다.

방식 띄어쓰기 경로 비고
os.execv(sys.executable, [...]) 잘린 경로로 넘어가 죽음 윈도우에서 따옴표를 붙이지 않음
subprocess.Popen([...]) 목록 정상 list2cmdline 이 따옴표로 감싸 줌
subprocess.Popen("문자열") 직접 따옴표를 넣어야 함 실수하기 쉬움

Popen 목록으로 새로 띄우고 스스로 끝내기

import os, sys, subprocess

DETACHED_PROCESS = 0x00000008
CREATE_NEW_PROCESS_GROUP = 0x00000200

def restart_self():
    script = os.path.abspath(sys.argv[0])
    subprocess.Popen(
        [sys.executable, script] + sys.argv[1:],
        creationflags=DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP,
        close_fds=True,
    )
    os._exit(0)

인자를 목록으로 넘기면 파이썬이 subprocess.list2cmdline 으로 띄어쓰기가 든 인자를 알아서 따옴표로 감쌉니다. 새 프로세스를 부모와 떼어 띄운 뒤, 지금 프로세스는 os._exit(0) 으로 바로 끝냅니다.

고칠 때 판 번호를 올리지 않는다

여기서 함정이 하나 더 있었습니다. 재시작 방식을 고친 새 판을 배포하면서 판 번호를 올리면, 디스크에 남은 옛 판이 그 새 판을 받아 옛 방식(execv)으로 재시작하다가 또 죽습니다.

그래서 재시작 방식만 고칠 때는 판 번호를 올리지 않고 파일을 바꿔 두었습니다. 옛 판이 업데이트를 받으러 가지 않게 하는 것이 핵심입니다.

고쳐졌는지 확인하는 법

멀리 있는 PC 에서 도는 프로그램이라면 로그 문구가 아니라 접속 간격으로 살아 있는지 봅니다. 3분마다 오던 접속이 재시작 뒤에도 같은 간격으로 이어지면 새 프로세스가 제대로 뜬 것입니다.

가까이 있는 PC 라면 띄어쓰기가 든 폴더에 스크립트를 두고 재시작 함수를 한 번 불러 본 뒤, 새 프로세스가 떠 있는지 프로세스 목록으로 확인하면 됩니다.

Get-CimInstance Win32_Process -Filter "Name like 'python%'" | Select-Object ProcessId, CommandLine

이 재현 절차는 따로 돌려 보지 못했습니다. 그래서 여기까지는 확인하지 못했고, 멀리 있는 PC 는 접속 간격을 기준으로 보기로 정했습니다.

왜 이렇게 늦게 알았나

이 문제는 평소에는 드러나지 않습니다. 재시작은 새 판이 나왔을 때만 일어나고, 개발하는 PC 의 폴더 이름에는 띄어쓰기가 없을 수도 있기 때문입니다. 띄어쓰기가 있는 폴더에 설치된 PC 에서 업데이트가 일어난 순간에만 죽습니다.

게다가 창 없이 도는 프로그램이라 죽는 장면을 볼 수 없었습니다. 멀리 있는 PC 의 프로그램이 스스로를 고치는 구조라면, 오류를 서버로 알리는 길과 접속 간격 같은 생존 신호를 처음부터 함께 만들어 두는 것이 좋습니다. 이번에도 결국 접속 간격이 유일한 단서였습니다.

확인한 환경

항목 내용
운영체제 윈도우 노트북
실행 방식 pythonw 로 도는 자기 갱신 프로그램
경로 조건 프로그램 폴더 이름에 띄어쓰기 포함

관련 글: pythonw 인데도 CMD 창이 뜰 때, 파이썬에서 실패가 조용히 삼켜지는 세 가지

이 글의 내용은 2026년 10월 5일에 마지막으로 확인했습니다. 틀린 곳을 발견하시면 연락처로 알려 주세요.