파이썬 os 모듈 총정리

파이썬 os 모듈 총정리

Cheetsheet os Module in python

개요 1

os 은 운영체제 종속 기능에 대한 간단한 명령을 모아놓은 기본 모듈이다. 파이썬을 사용하는 이유 중 하나가 빠르고 간편하게 프로그램을 작성하기 용이하다는 것인데, 상식적으로 있어야할 기능들이 shutil 모듈과 혼재되어 있어 무척 불편하다. 파일 시스템을 다룰 땐 두 모듈을 고르게 사용해야한다.

총정리지만 단순히 공식 다큐먼트를 긁어온 게 아니라 가능하면 실제로 쓰는 기능들 위주로 설명했으니 모든 정보를 갖추진 않았다. 이 포스트에서 찾는 기능이 없다면 공식 다큐먼트를 확인하자.

이하 목차는 문서 순서가 아니라 경험적인 활용도 순서로 작성되었다. 위쪽에 있을수록 빈번하게 쓰인다. 목차 자체를 치트시트로 보고 원하는 함수를 빠르게 찾아보도록 하자.

os 모듈로 할 수 없는 것

커맨드라인을 통한 파일 복사, 삭제 이동, 이름 변경이 불가능하다. 리눅스 터미널에선 가능하지만, 윈도 cmd나 powershell에선 불가능하다. os.system("foo ... ...")으로 가능할 것 같지만 'foo'은(는) 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는 배치 파일이 아닙니다.라는 경고와 함께 실패한다.

가령 os.system("rm a.txt")와 같은 명령을 내리면 a.txt를 삭제하라는 말인데, 그 대신 해당 기능을 가진 함수 os.remove("a.txt")를 따로 사용해야한다.

이렇듯 커맨드라인으로 접근하지 않고 모듈에서 제공하는 함수를 쓰는 방식이 반드시 나쁘다는 것은 아니다. 기능이 적절하지 못하게 쓰였을 때 에러를 레이즈하고 경고해주는 것은 안전한 프로그래밍에 있어서 중요한 일이다. 문제의 핵심은 이들의 기능과 이름이 매칭이 잘 되지 않거나 무척 헷갈린다는 것이다.

os 직속 메소드

os의 가장 짜증나는 부분은 네이밍이 리눅스 명령어랑 너무 다르다는 것이고, 그 다음으로 짜증나는 것은 그 다른 네이밍끼리 일관성이 떨어진다는 것이다. 파이썬만 파는 사람이야 큰 문제가 없지만 멀티랭귀지를 구사한다면 상당히 괴로워진다.

현재 작업 경로 확인 getcwd()

current work directory를 get한다는 의미다. 현재 디렉터리를 문자열로 리턴한다.

작업 경로 변경 chdir()

문자열로 주어진 디렉터리로 작업 경로를 변경한다.

파일 목록 listdir()

directory의 list라는 의미다.

listdirs(path='.')

  • path: 입력한 문자열대로의 경로에 있는 파일의 목록을 제공한다. 아무것도 입력하지 않으면 현재 작업 경로의 파일 리스트를 리턴한다.

만약 현재 경로에서 확장자가 .txt인 파일의 목록만 얻고 싶다면 그 코드는 다음과 같다.2

files = os.listdir()
txt_files = [file for file in files if file.endswith(".txt")]

커맨드라인 명령 system()

system(command)

  • command: 문자열로 주어지며, 해당 명령을 터미널에서 실행시킨다. 업무 자동화, 모니터링, 서버 순회등을 위한 쉘 스크립트 등에 요긴하게 쓰인다.

그 외에 프로그램을 일시정지 하고싶다면 그 코드는 다음과 같이 쓸 수 있다.

import os
os.system("pause")

새 폴더 생성 mkdirs(), makedirs()

mkdir(path, mode=0o777, *, dir_fd=None)

  • path: 현재 작업 경로에 입력한 문자열을 이름으로 갖는 폴더를 생성한다. 디렉터리가 이미 존재하면, FileExistsError가 발생한다.

makedirs(name, mode=0o777, exist_ok=False)

  • name: 입력한 문자열대로의 이름을 가진 폴더를 생성한다. 슬래시 /를 통해 하위 디렉터리까지 만들 수 있다.
  • exist_ok: 이미 해당 경로가 존재해도 되는지에 대한 여부다. 참이면 경로가 이미 존재해도 문제 없고, 거짓(디폴트)이면 FileExistsError를 레이즈한다.

예를 들어, ./ 에서 ./main 의 하위 폴더인 sub 폴더까지 한번에 FileExistsError 없이 생성하고 싶다면 그 코드는 다음과 같다.

os.makedirs("main/sub", exist_ok=True)

삭제 remove(), rmdir(), removedirs()

remove()

  • 파일을 삭제하기 위한 함수다.
  • 주어진 경로가 디렉터리면 IsADirectoryError를 레이즈한다.
  • 파일이 존재하지 않으면 FileNotFoundError를 레이즈한다.

rmdir()

  • 디렉터리를 제거하기 위한 함수다.
  • 디렉터리가 존재하지 않거나 비어있지 않으면 FileNotFoundError를 레이즈한다.

어차피 디렉터리를 삭제하는 함수 이름이 rmdir()이면 그냥 파일을 삭제하는 함수는 rm()이어도 상관 없지 않나? 싶은 생각이 가장 먼저 든다. 심지어 rmdir()은 디렉터리가 비어있어야한다는 점에서 쓰기도 어렵다. 커맨드라인이라면 -r(재귀) 옵션을 넣어서 하위 경로도 한번에 정리할 수 있을텐데, 이 함수에는 그런 기능도 없다. 하위 트리를 포함해서 삭제하려면 shutil 모듈의 shutil.rmtree()를 사용해야한다. 그리고 이런 기괴한 이름 문제의 원흉은 아마도 다음의 함수일 것이다.

removedirs()

  • 말단 디렉터리 안에 파일이 없으면 삭제한다.
  • 삭제하는 것에 성공하면 거꾸로 상위 디렉터리를 타고 올라오면서 빈 폴더면 삭제한다. 즉 재귀적으로 디렉터리를 제거하는건데, 왜 하위가 아니라 상위로 삭제하는 함수를 ‘우선적으로’ 지원하는지는 알 수 없는 일이다. 보통의 상황에서 프로그래머에게 필요한 것은 shutil.rmtree()와 같은 기능이기 때문이다.
  • 이 함수를 편리하게 쓸 수 없다는 말은 아니다. 단지 기능과 이름을 매치시키기 어렵고 외우기가 어려우며, 경로를 거꾸로 타고 올라온다는 점이 의도하지 않은 부작용으로 이어질 위험이 클 뿐이다.

이름 변경, 이동 rename(), renames(), replace()

rename(src, dst, *, src_dir_fd=None, dst_dir_fd=None)

  • src의 이름을 dst으로 바꾸는데, 만약 dst가 이미 존재하면 FileExistsError를 레이즈한다.
  • dst의 경로는 말단 디렉터리를 제외하고는 존재해야한다. 다시 말해, ./a.txt./temp/b.txt 로 바꾸고 싶다면 ./temp 폴더가 존재해야한다.

renames(old, new)

  • old의 이름을 new로 재귀적으로 바꾼다. ./a.txt./temp/b.txt 로 바꾸고 싶을 때 ./temp 폴더가 존재하지 않는다면 ./temp를 스스로 만들고 b.txt를 그 아래에 넣어준다.

replace(src, dst, *, src_dir_fd=None, dst_dir_fd=None)

  • rename()이랑 같은 함수인데, rename()은 플랫폼에 따라 다른 에러를 레이즈하지만 replace()는 플랫폼을 가리지 않는 차이점이 있다.

path

문자열 핸들링 join(), split()

path.join(path, *paths)

  • 복수의 문자열을 이어붙여서 디렉터리를 나타내는 문자열로 리턴한다.

path.split(path)

  • 주어진 디렉터리의 문자열을 문자열의 튜플 (head, tail)로 리턴한다. tail은 말단 요소고, head는 그 상위 디렉터리들이다.

존재성 체크 exsits(), isfile(), isdir()

path.exists(path)

  • path가 존재하면 참을 리턴한다.

path.isfile(path)

  • path가 존재하는 파일이면 참을 리턴한다.

path.isdir(path)

  • path가 존재하는 디렉터리면 참을 리턴한다.

환경

  • OS: Windows
  • Python: 3.9.4

  1. https://docs.python.org/ko/3/library/os.html ↩︎

  2. https://hyeshinoh.github.io/2018/10/12/python_09_OS%20&%20shutil/ ↩︎

댓글