# `shlex` — 간단한 어휘 분석

소스 코드: Lib/shlex.py

`shlex` 클래스를 사용하면 유닉스 셸과 유사한 간단한 구문에 대한 어휘 분석기를 쉽게 작성할 수 있습니다. 이것은 미니 언어를 작성하거나 (예를 들어 파이썬 응용 프로그램을 위한 실행 제어 파일에서), 인용된 문자열을 구문 분석할 때 유용합니다.

`shlex` 모듈은 다음 함수를 정의합니다:

`shlex.``split`(s, comments=False, posix=True)

  셸과 비슷한 문법을 사용하여 문자열 s를 분할합니다. comments가 `False`(기본값)이면, 지정된 문자열의 주석 구문 분석이 비활성화됩니다 (`shlex` 인스턴스의 `commenters` 어트리뷰트를 빈 문자열로 설정합니다). 이 함수는 기본적으로 POSIX 모드로 작동하지만, posix 인자가 거짓이면 비 POSIX 모드를 사용합니다.

  참고

  `split()` 함수는 `shlex` 인스턴스를 인스턴스화 하므로, s에 `None`을 전달하면 표준 입력에서 분할할 문자열을 읽습니다.

  버전 3.9부터 폐지: s에 `None`을 전달하면 향후 파이썬 버전에서 예외가 발생할 것입니다.

`shlex.``join`(split_command)

  리스트 split_command의 토큰을 이어붙이고 문자열을 반환합니다. 이 함수는 `split()`의 역함수입니다.

      >>> from shlex import join
      >>> print(join(['echo', '-n', 'Multiple words']))
      echo -n 'Multiple words'

  반환된 값은 주입 취약점(injection vulnerabilities)으로부터 보호하기 위해 셸 이스케이프 처리됩니다 (`quote()`를 참조하십시오).

  버전 3.8에 추가.

`shlex.``quote`(s)

  셸 이스케이프 된 문자열 s를 반환합니다. 반환된 값은 (리스트를 사용할 수 없는 경우) 셸 명령 줄에서 하나의 토큰으로 안전하게 사용할 수 있는 문자열입니다.

  이 관용구는 안전하지 않습니다:

      >>> 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 ~'"'"''

  인용(quoting)은 유닉스 셸과 `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 ~']

  버전 3.3에 추가.

`shlex` 모듈은 다음 클래스를 정의합니다:

class `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`는 파이썬 3.5와 이전 버전에서의 동작을 유지합니다. `True`로 설정되면, 문자 `();<>|&`의 구문 분석이 변경됩니다: 이러한 문자(구두(punctuation) 문자로 간주합니다)의 모든 연속은 단일 토큰으로 반환됩니다. 비어 있지 않은 문자열로 설정하면, 해당 문자는 구두(punctuation) 문자로 사용됩니다. punctuation_chars에 나타나는 `wordchars` 어트리뷰트의 문자는 `wordchars`에서 제거됩니다. 자세한 정보는 셸과의 호환성 향상을 참조하십시오. punctuation_chars는 `shlex` 인스턴스 생성 시에만 설정할 수 있으며 나중에 수정할 수 없습니다.

  버전 3.6에서 변경: punctuation_chars 매개 변수가 추가되었습니다.

더 보기

모듈 `configparser`

  윈도우 `.ini` 파일과 유사한 구성 파일 구문 분석기.

## shlex 객체

`shlex` 인스턴스에는 다음과 같은 메서드가 있습니다:

`shlex.``get_token`()

  토큰을 반환합니다. `push_token()`을 사용하여 토큰이 스택(stack) 되었으면, 스택에서 토큰을 팝(pop) 합니다. 그렇지 않으면, 입력 스트림에서 하나를 읽습니다. 읽기가 즉시 파일 끝을 만나면, `eof`가 반환됩니다 (POSIX 모드가 아니면 빈 문자열 (`''`), POSIX 모드이면 `None`).

`shlex.``push_token`(str)

  인자를 토큰 스택으로 푸시(push)합니다.

`shlex.``read_token`()

  원시 토큰을 읽습니다. 푸시백 스택을 무시하고, 소스 요청(source requests)을 해석하지 않습니다. (이것은 일반적으로 유용한 진입점이 아니며, 단지 완전성을 위해 여기에서 설명합니다.)

`shlex.``sourcehook`(filename)

  `shlex`가 소스 요청(아래 `source`를 참조하십시오)을 감지할 때 이 메서드에는 다음 토큰이 인자로 제공되고 파일명과 열린 파일류 객체로 구성된 튜플을 반환해야 합니다.

  일반적으로, 이 메서드는 먼저 인자에서 인용(quotes)을 제거합니다. 결과가 절대 경로명이거나 유효한 이전 소스 요청이 없거나 이전 소스가 스트림(가령 `sys.stdin`)이면 결과는 그대로 유지됩니다. 그렇지 않으면, 결과가 상대 경로명이면 소스 포함 스택에서 파일 바로 앞에 있는 파일의 이름의 디렉터리 부분을 앞에 붙입니다 (이 동작은 C 전처리기가 `#include "file.h"`를 처리하는 방식과 유사합니다).

  조작 결과는 파일명으로 취급되고, 튜플의 첫 번째 구성 요소로 반환되며, 이것에 `open()`이 호출되어 두 번째 구성 요소를 산출합니다. (참고: 이것은 인스턴스 초기화의 인자 순서와 반대입니다!)

  이 훅은 디렉터리 검색 경로, 파일 확장자 추가 및 기타 네임 스페이스 해킹을 구현하는 데 사용할 수 있도록 노출됩니다. 해당 ‘닫기’ 훅은 없지만, shlex 인스턴스는 소스 입력 스트림이 EOF를 반환할 때 그것의 `close()` 메서드를 호출합니다.

  소스 스태킹을 더 명시적으로 제어하려면, `push_source()`와 `pop_source()` 메서드를 사용하십시오.

`shlex.``push_source`(newstream, newfile=None)

  입력 소스 스트림을 입력 스택으로 푸시합니다. filename 인자가 지정되면 나중에 에러 메시지에 사용할 수 있습니다. 이것은 `sourcehook()` 메서드에 의해 내부적으로 사용되는 것과 같은 메서드입니다.

`shlex.``pop_source`()

  마지막으로 푸시 된 입력 소스를 입력 스택에서 팝 합니다. 이는 어휘 분석기가 스택 된 입력 스트림에서 EOF에 도달할 때 내부적으로 사용되는 것과 같은 메서드입니다.

`shlex.``error_leader`(infile=None, lineno=None)

  이 메서드는 유닉스 C 컴파일러 에러 레이블 형식으로 에러 메시지 리더를 생성합니다; 형식은 `'"%s", line %d: '`이며, 여기서 `%s`는 현재 소스 파일의 이름으로 치환되고 `%d`는 현재 입력 줄 번호로 치환됩니다 (선택적 인자를 사용하여 이를 재정의할 수 있습니다).

  이 편리 메서드는 `shlex` 사용자가 Emacs와 기타 유닉스 도구가 이해할 수 있는 표준의 구문 분석 가능한 형식으로 에러 메시지를 생성하도록 권장하기 위해 제공됩니다.

`shlex` 서브 클래스의 인스턴스에는 어휘 분석을 제어하거나 디버깅에 사용할 수 있는 일부 공용 인스턴스 변수가 있습니다:

`shlex.``commenters`

  주석을 시작하는 것으로 인식되는 문자열. 주석 시작부터 줄 끝까지의 모든 문자는 무시됩니다. 기본적으로 `'#'` 만 포함합니다.

`shlex.``wordchars`

  다중 문자 토큰에 누적될 문자들의 문자열. 기본적으로, 모든 ASCII 영숫자와 밑줄이 포함됩니다. POSIX 모드에서는, 라틴-1 집합의 악센트 부호 문자도 포함됩니다. `punctuation_chars`가 비어 있지 않으면, 파일명 명세와 명령 줄 매개 변수에 나타날 수 있는 문자 `~-./*?=`도 이 어트리뷰트에 포함되며, `punctuation_chars`에 있는 문자는 `wordchars`에 있으면 제거됩니다. `whitespace_split`이 `True`로 설정되면, 이것은 효과가 없습니다.

`shlex.``whitespace`

  공백으로 간주하여 건너뛸 문자들. 공백은 토큰의 경계를 만듭니다. 기본적으로, 스페이스, 탭, 줄 바꿈 및 캐리지 리턴이 포함됩니다.

`shlex.``escape`

  이스케이프로 간주하는 문자들. POSIX 모드에서만 사용되며, 기본적으로 `'\'` 만 포함합니다.

`shlex.``quotes`

  문자열 인용으로 간주하는 문자들. 같은 인용을 다시 만날 때까지 토큰이 누적됩니다 (따라서, 다른 인용 유형은 셸에서와같이 서로를 보호합니다). 기본적으로, ASCII 작은따옴표와 큰따옴표가 포함됩니다.

`shlex.``escapedquotes`

  `escape`에 정의된 이스케이프 문자를 해석하는 `quotes`의 문자들. 이것은 POSIX 모드에서만 사용되며, 기본적으로 `'"'` 만 포함합니다.

`shlex.``whitespace_split`

  `True`이면, 토큰은 공백으로만 분할됩니다. 예를 들어, `shlex`로 명령 줄을 구문 분석하고 셸 인자와 유사한 방식으로 토큰을 가져오는 데 유용합니다. `punctuation_chars`와 함께 사용하면, 토큰은 그 문자들 외에도 공백으로 분할됩니다.

  버전 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`

  읽기 전용 프로퍼티. 구두 부호로 간주할 문자들. 구두 부호 문자들은 단일 토큰으로 반환됩니다. 그러나, 아무런 의미 유효성 검사도 수행되지 않음에 유의하십시오: 예를 들어 ‘>>>’는 셸에서 인식되지 않더라도 토큰으로 반환될 수 있습니다.

  버전 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` 값으로 알립니다;

- 인용된 빈 문자열(`''`)이 허용됩니다.

## 셸과의 호환성 향상

버전 3.6에 추가.

`shlex` 클래스는 `bash`, `dash` 및 `sh`와 같은 일반적인 유닉스 셸에서 수행하는 구문 분석과 호환됩니다. 이 호환성을 이용하려면, 생성자에서 `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']

참고

`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`의 기본값임에 유의하십시오.)