shlex — 간단한 어휘 분석
shlex — 간단한 어휘 분석
shlex 클래스는 Unix 셸과 유사한 간단한 문법에 대한 어휘 분석기를 쉽게 작성할 수 있게 합니다. 이것은 미니 언어 작성(Python 응용 프로그램의 실행 제어 파일 등)이나 따옴표 붙은 문자열 파싱에 자주 유용합니다.
본문
shlex 모듈은 다음 함수를 정의합니다.
shlex.split(s, comments=False, posix=True)
셸과 유사한 문법을 사용하여 문자열 s를 분할합니다. comments가 False(기본값)이면 주어진 문자열의 주석 파싱이 비활성화됩니다(shlex 인스턴스의 commenters 속성을 빈 문자열로 설정). 이 함수는 기본적으로 POSIX 모드에서 작동하지만 posix 인자가 거짓이면 비-POSIX 모드를 사용합니다.
versionchanged: 3.12에서
s인자에None을 전달하면sys.stdin을 읽는 대신 예외를 발생시킵니다.
shlex.join(split_command)
목록 split_command의 토큰을 연결하고 문자열을 반환합니다. 이 함수는 split()의 역함수입니다.
>>> from shlex import join
>>> print(join(['echo', '-n', 'Multiple words']))
echo -n 'Multiple words'
반환 값은 주입 공격으로부터 보호하기 위해 셸 이스케이프됩니다(quote() 참고).
versionadded: 3.8.
shlex.quote(s)
문자열 s의 셸 이스케이프 버전을 반환합니다. 반환 값은 셸 명령줄에서 하나의 토큰으로 안전하게 사용할 수 있는 문자열입니다(목록을 사용할 수 없는 경우).
Warning
shlex모듈은 Unix 셸만 위해 설계되었습니다.quote()함수는 POSIX 준수 셸이나 Windows와 같은 다른 운영 체제의 셸에서 올바름이 보장되지 않습니다. 그러한 셸에서 이 모듈로 따옴표 처리한 명령을 실행하면 명령 주입 취약점의 가능성이 열릴 수 있습니다.
subprocess.run()을shell=False로 사용하는 것과 같이 명령 인자를 목록으로 전달하는 함수를 사용하는 것을 고려하세요.이 관용구는 안전하지 않습니다:
>>> filename = 'somefile; rm -rf ~' >>> command = 'ls -l {}'.format(filename) >>> print(command) # executed by a shell: boom! ls -l somefile; rm -rf ~
quote()는 보안 구멍을 막아줍니다:>>> from shlex import quote >>> command = 'ls -l {}'.format(quote(filename)) >>> print(command) ls -l 'somefile; rm -rf ~' >>> remote_command = 'ssh home {}'.format(quote(command)) >>> print(remote_command) ssh home 'ls -l '"'"'somefile; rm -rf ~'"'"''따옴표 처리는 UNIX 셸 및
split()과 호환됩니다:>>> from shlex import split >>> remote_command = split(remote_command) >>> remote_command ['ssh', 'home', "ls -l 'somefile; rm -rf ~'"] >>> command = split(remote_command[-1]) >>> command ['ls', '-l', 'somefile; rm -rf ~']
versionadded: 3.3.
shlex 모듈은 다음 클래스를 정의합니다.
shlex.shlex(instream=None, infile=None, posix=False, punctuation_chars=False)
shlex 인스턴스 또는 하위 클래스 인스턴스는 어휘 분석기 객체입니다. 초기화 인자(있는 경우)는 문자를 읽을 위치를 지정합니다. read()와 readline() 메서드를 가진 파일/스트림과 유사한 객체이거나 문자열이어야 합니다. 인자가 없으면 입력은 sys.stdin에서 가져옵니다. 두 번째 선택적 인자는 infile 속성의 초기 값을 설정하는 파일 이름 문자열입니다. instream 인자가 생략되거나 sys.stdin과 같으면 이 두 번째 인자는 "stdin"으로 기본값이 지정됩니다. posix 인자는 작동 모드를 정의합니다: posix가 참이 아닐 때(기본값) shlex 인스턴스는 호환성 모드에서 작동합니다. POSIX 모드에서 작동할 때 shlex는 POSIX 셸 파싱 규칙에 가능한 한 가깝게 되도록 노력합니다. punctuation_chars 인자는 실제 셸이 파싱하는 방식에 더 가깝게 동작하게 하는 방법을 제공합니다. 이것은 여러 값을 가질 수 있습니다: 기본값 False는 Python 3.5 및 이전에서 보인 동작을 보존합니다. True로 설정하면 ();<>|& 문자의 파싱이 변경됩니다: 이 문자들(구두점 문자로 간주)의 연속 실행은 단일 토큰으로 반환됩니다. 비어 있지 않은 문자열로 설정하면 그 문자들이 구두점 문자로 사용됩니다. punctuation_chars에 나타나는 wordchars 속성의 문자는 wordchars에서 제거됩니다. 자세한 내용은 셸과의 개선된 호환성(Improved Compatibility with Shells)을 참고하세요. punctuation_chars는 shlex 인스턴스 생성 시에만 설정할 수 있으며 나중에 수정할 수 없습니다.
versionchanged: 3.6에서
punctuation_chars매개변수가 추가되었습니다.
See also
Module configparser — Windows .ini 파일과 유사한 구성 파일용 파서.
shlex 객체
shlex 인스턴스는 다음 메서드를 가집니다.
- shlex.get_token() — 토큰을 반환합니다.
push_token()을 사용하여 토큰을 스택에 넣었다면 스택에서 토큰을 꺼냅니다. 그렇지 않으면 입력 스트림에서 하나를 읽습니다. 읽기가 즉시 파일 끝에 도달하면eof가 반환됩니다(비-POSIX 모드에서는 빈 문자열(''), POSIX 모드에서는None). - shlex.push_token(str) — 인자를 토큰 스택에 넣습니다.
- shlex.read_token() — 원시 토큰을 읽습니다. pushback 스택을 무시하고 소스 요청을 해석하지 않습니다. (이것은 보통 유용한 진입점이 아니며 완전성을 위해서만 여기에 문서화되어 있습니다.)
- shlex.sourcehook(filename) —
shlex가 소스 요청을 감지하면(source참고) 이 메서드는 다음 토큰을 인자로 받고 파일 이름과 열린 file-like 객체로 구성된 튜플을 반환할 것으로 예상됩니다.- 일반적으로 이 메서드는 먼저 인자에서 따옴표를 제거합니다. 결과가 절대 경로명이거나, 이전 소스 요청이 적용되지 않았거나, 이전 소스가 스트림(
sys.stdin과 같은)이면 결과는 그대로 둡니다. 그렇지 않으면 결과가 상대 경로명이면 소스 포함 스택에서 바로 앞의 파일 이름의 디렉터리 부분이 앞에 붙습니다(이 동작은 C 전처리기가#include "file.h"를 처리하는 방식과 같습니다). - 조작의 결과는 파일 이름으로 처리되어 튜플의 첫 번째 구성 요소로 반환되고, 두 번째 구성 요소를 생성하기 위해 그 위에서
open()이 호출됩니다. (참고: 이것은 인스턴스 초기화의 인자 순서의 역순입니다!) - 이 훅은 디렉터리 검색 경로, 파일 확장자 추가, 기타 네임스페이스 해킹을 구현하는 데 사용할 수 있도록 노출됩니다. 대응하는 'close' 훅은 없지만 shlex 인스턴스는 EOF를 반환할 때 소스 입력 스트림의
close()메서드를 호출합니다. - 소스 스태킹을 더 명시적으로 제어하려면
push_source()와pop_source()메서드를 사용하세요.
- 일반적으로 이 메서드는 먼저 인자에서 따옴표를 제거합니다. 결과가 절대 경로명이거나, 이전 소스 요청이 적용되지 않았거나, 이전 소스가 스트림(
- shlex.push_source(newstream, newfile=None) — 입력 스택에 입력 소스 스트림을 넣습니다. 파일 이름 인자가 지정되면 나중에 오류 메시지에서 사용할 수 있습니다. 이것은
sourcehook()메서드가 내부적으로 사용하는 것과 같은 메서드입니다. - shlex.pop_source() — 입력 스택에서 마지막으로 넣은 입력 소스를 꺼냅니다. 스택된 입력 스트림에서 어휘 분석기가 EOF에 도달할 때 내부적으로 사용하는 것과 같은 메서드입니다.
- shlex.error_leader(infile=None, lineno=None) — Unix C 컴파일러 오류 라벨 형식의 오류 메시지 리더를 생성합니다. 형식은
'"%s",line%d:'이며%s는 현재 소스 파일 이름으로,%d는 현재 입력 줄 번호로 대체됩니다(선택적 인자로 재정의할 수 있습니다).- 이 편의 기능은 shlex 사용자가 Emacs 및 기타 Unix 도구가 이해하는 표준 파서 가능 형식으로 오류 메시지를 생성하도록 권장하기 위해 제공됩니다.
shlex 하위 클래스의 인스턴스는 어휘 분석을 제어하거나 디버깅에 사용할 수 있는 몇 가지 공개 인스턴스 변수를 가집니다.
- shlex.commenters — 주석 시작으로 인식되는 문자 문자열. 주석 시작부터 줄 끝까지의 모든 문자는 무시됩니다. 기본적으로
'#'만 포함합니다. - shlex.wordchars — 여러 문자 토큰으로 축적될 문자 문자열. 기본적으로 모든 ASCII 영숫자와 밑줄을 포함합니다. POSIX 모드에서는 Latin-1 집합의 악센트 있는 문자도 포함합니다.
punctuation_chars가 비어 있지 않으면 파일 이름 지정과 명령줄 매개변수에서 나타날 수 있는~-./*?=문자도 이 속성에 포함되고,punctuation_chars에 나타나는 문자는wordchars에 있으면 제거됩니다.whitespace_split이True로 설정되면 효과가 없습니다. - shlex.whitespace — 공백으로 간주되어 건너뛰는 문자. 공백은 토큰을 묶습니다. 기본적으로 공백, 탭, 줄 바꿈, 캐리지 리턴을 포함합니다.
- shlex.escape — 이스케이프로 간주되는 문자. POSIX 모드에서만 사용되며 기본적으로
'\\'만 포함합니다. - shlex.quotes — 문자열 따옴표로 간주되는 문자. 같은 따옴표가 다시 만날 때까지 토큰이 축적됩니다(따라서 다른 따옴표 유형은 셸에서처럼 서로를 보호합니다). 기본적으로 ASCII 작은따옴표와 큰따옴표를 포함합니다.
- shlex.escapedquotes —
escape에 정의된 이스케이프 문자를 해석할 따옴표 안의 문자. POSIX 모드에서만 사용되며 기본적으로'"'만 포함합니다. - shlex.whitespace_split —
True이면 토큰은 공백에서만 분할됩니다. 예를 들어 셸 인자와 유사한 방식으로 토큰을 얻기 위해 shlex로 명령줄을 파싱하는 데 유용합니다.punctuation_chars와 함께 사용하면 그 문자들 외에도 공백에서 토큰이 분할됩니다.versionchanged: 3.8에서
punctuation_chars속성이whitespace_split속성과 호환되게 되었습니다. - shlex.infile — 현재 입력 파일의 이름. 클래스 인스턴스화 시 처음 설정되거나 이후 소스 요청에 의해 스택됩니다. 오류 메시지를 구성할 때 이것을 검사하는 것이 유용할 수 있습니다.
- shlex.instream — 이 shlex 인스턴스가 문자를 읽는 입력 스트림.
- shlex.source — 기본적으로
None인 이 속성. 문자열을 할당하면 그 문자열이 다양한 셸의source키워드와 유사한 어휘 수준 포함 요청으로 인식됩니다. 즉, 바로 다음 토큰이 파일 이름으로 열리고 입력이 그 스트림에서 EOF까지 취해지며, 그 시점에서 그 스트림의close()메서드가 호출되고 입력 소스는 다시 원래 입력 스트림이 됩니다. 소스 요청은 원하는 수준 깊이로 스택될 수 있습니다. - shlex.debug — 이 속성이 숫자이고 1 이상이면 shlex 인스턴스는 그 동작에 대해 상세 진행 출력을 인쇄합니다. 이것을 사용해야 한다면 세부 사항을 배우기 위해 모듈 소스 코드를 읽을 수 있습니다.
- shlex.lineno — 소스 줄 번호(지금까지 본 줄 바꿈 수 + 1).
- shlex.token — 토큰 버퍼. 예외를 잡을 때 이것을 검사하는 것이 유용할 수 있습니다.
- shlex.eof — 파일 끝을 결정하는 데 사용되는 토큰. 비-POSIX 모드에서는 빈 문자열
(''), POSIX 모드에서는None으로 설정됩니다. - shlex.punctuation_chars — 읽기 전용 속성. 구두점으로 간주되는 문자. 구두점 문자의 연속 실행은 단일 토큰으로 반환됩니다. 단, 의미론적 유효성 검사는 수행되지 않습니다. 예를 들어
'>>>'는 셸이 그렇게 인식하지 못할 수 있어도 토큰으로 반환될 수 있습니다.versionadded: 3.6.
파싱 규칙
비-POSIX 모드에서 작동할 때 shlex는 다음 규칙을 따르려고 노력합니다.
- 따옴표 문자는 단어 안에서 인식되지 않습니다(
Do"Not"Separate는 단일 단어Do"Not"Separate로 파싱됩니다). - 이스케이프 문자는 인식되지 않습니다.
- 따옴표로 문자를 감싸면 따옴표 안의 모든 문자의 리터럴 값을 보존합니다.
- 닫는 따옴표는 단어를 구분합니다(
"Do"Separate는"Do"와Separate로 파싱됩니다). whitespace_split이False이면 단어 문자, 공백 또는 따옴표로 선언되지 않은 문자는 단일 문자 토큰으로 반환됩니다.True이면 shlex는 공백에서만 단어를 분할합니다.- EOF는 빈 문자열
('')로 신호됩니다. - 따옴표로 감싸더라도 빈 문자열을 파싱하는 것은 불가능합니다.
POSIX 모드에서 작동할 때 shlex는 다음 파싱 규칙을 따르려고 노력합니다.
- 따옴표는 제거되고 단어를 구분하지 않습니다(
"Do"Not"Separate"는 단일 단어DoNotSeparate로 파싱됩니다). - 따옴표로 감싸지 않은 이스케이프 문자(예:
'\')는 뒤따르는 다음 문자의 리터럴 값을 보존합니다. escapedquotes의 일부가 아닌 따옴표(예:"'")로 문자를 감싸면 따옴표 안의 모든 문자의 리터럴 값을 보존합니다.escapedquotes의 일부인 따옴표(예:'"')로 문자를 감싸면escape에 언급된 문자를 제외한 따옴표 안의 모든 문자의 리터럴 값을 보존합니다. 이스케이프 문자는 사용 중인 따옴표 또는 이스케이프 문자 자체가 뒤따를 때만 특별한 의미를 유지합니다. 그렇지 않으면 이스케이프 문자는 일반 문자로 간주됩니다.- EOF는
None값으로 신호됩니다. - 따옴표로 감싼 빈 문자열
('')은 허용됩니다.
셸과의 개선된 호환성
versionadded: 3.6.
shlex 클래스는 bash, dash, sh와 같은 일반적인 Unix 셸이 수행하는 파싱과의 호환성을 제공합니다. 이 호환성을 활용하려면 생성자에서 punctuation_chars 인자를 지정하세요. 이것은 기본적으로 False이며 3.6 이전 동작을 보존합니다. 그러나 True로 설정하면 ();<>|& 문자의 파싱이 변경됩니다: 이 문자들의 연속 실행은 단일 토큰으로 반환됩니다. 이것은 셸의 완전한 파서에는 미치지 못하지만(표준 라이브러리의 범위를 벗어날 만큼 많은 셸이 존재하므로), 그렇지 않을 때보다 더 쉽게 명령줄 처리를 수행할 수 있게 합니다. 다음 스니펫에서 차이를 볼 수 있습니다:
>>> import shlex
>>> text = "a && b; c && d || e; f >'abc'; (def \"ghi\")"
>>> s = shlex.shlex(text, posix=True)
>>> s.whitespace_split = True
>>> list(s)
['a', '&&', 'b;', 'c', '&&', 'd', '||', 'e;', 'f', '>abc;', '(def', 'ghi)']
>>> s = shlex.shlex(text, posix=True, punctuation_chars=True)
>>> s.whitespace_split = True
>>> list(s)
['a', '&&', 'b', ';', 'c', '&&', 'd', '||', 'e', ';', 'f', '>', 'abc', ';',
'(', 'def', 'ghi', ')']
물론 셸에 유효하지 않은 토큰이 반환될 것이며 반환된 토큰에 대한 자체 오류 검사를 구현해야 합니다.
punctuation_chars 매개변수의 값으로 True를 전달하는 대신 특정 문자가 포함된 문자열을 전달할 수 있으며, 이것은 어떤 문자가 구두점을 구성하는지 결정하는 데 사용됩니다. 예:
>>> import shlex
>>> s = shlex.shlex("a && b || c", punctuation_chars="|")
>>> list(s)
['a', '&', '&', 'b', '||', 'c']
Note
punctuation_chars가 지정되면wordchars속성에~-./*?=문자가 추가됩니다. 그 이유는 이 문자들이 파일 이름(와일드카드 포함)과 명령줄 인자(예:--color=auto)에 나타날 수 있기 때문입니다. 따라서:>>> import shlex >>> s = shlex.shlex('~/a && b-c --color=auto || d *.py?', ... punctuation_chars=True) >>> list(s) ['~/a', '&&', 'b-c', '--color=auto', '||', 'd', '*.py?']그러나 셸에 최대한 가깝게 일치시키려면
punctuation_chars를 사용할 때 항상posix와whitespace_split을 사용하는 것이 좋으며, 이는wordchars를 완전히 무효화합니다.
최상의 효과를 위해 punctuation_chars는 posix=True와 함께 설정해야 합니다. (posix=False가 shlex의 기본값입니다.)