Модуль shlex
реализует функции для анализа синтаксиса оболочки Unix. Его можно использовать для написания предметно-ориентированного языка или для анализа и разбора строк в кавычках.
Общей проблемой при работе с вводимым текстом является идентификация последовательности цитируемых слов как единого объекта. Разделение текста на кавычки не всегда работает должным образом, особенно если есть вложенные уровни кавычек.
Наивным подходом было бы создание регулярного выражения для поиска частей текста вне кавычек, чтобы отделить их от текста внутри кавычек или наоборот. Это было бы излишне сложно и склонно к ошибкам, возникающим в результате крайних случаев, таких как апострофы или даже опечатки. Лучшее решение - использовать настоящий синтаксический анализатор, такой как предоставленный модулем shlex
.
При работе в режиме, отличном от POSIX, shlex
будет пытаться соблюдать следующие правила:
Do"Not"Separate
, разбирается как одно слово Do"Not"Separate
;sh.whitespace_split
имеет значение False
, любой символ, не объявленный как символ слова, пробел или кавычка, будет возвращен как односимвольный токен. Если sh.whitespace_split
имеет значение True
, то shlex
будет разбивать слова только в пробелах;''
;При работе в режиме POSIX, shlex
будет пытаться соблюдать следующие правила синтаксического анализа:
Do"Not"Separate
будет выглядеть как DoNotSeparate
\
сохраняют буквальное значение символа, следующего за ним;sh.escapedquotes
, например "'"
, сохраняет буквальное значение всех символов внутри кавычек;sh.escapedquotes
, например '"'
, сохраняет буквальное значение всех символов внутри кавычек, за исключением символов, упомянутых в shlex.escape. Экранирующие символы сохраняют свое особое значение только тогда, когда за ними следует используемая кавычка или сам экранирующий символ.''
разрешены.Разбор строки с кавычками:
import shlex >>> text = """This string has embedded "double quotes" and ... 'single quotes' in it, and even "a 'nested example'".""" >>> lexer = shlex.shlex(text) >>> for token in lexer: ... print('{!r}'.format(token)) ... # 'This' # 'string' # 'has' # 'embedded' # '"double quotes"' # 'and' # "'single quotes'" # 'in' # 'it' # ',' # 'and' # 'even' # '"a \'nested example\'"' # '.'
Правильное экранирование пробелов и метасимволов в строках команд терминальной оболочки:
>>> import shlex # Эта идиома была бы небезопасна: >>> filename = 'somefile; rm -rf ~' >>> command = f'ls -l {filename}' >>> print(command) # ls -l somefile; rm -rf ~ # quote() позволяет закрыть дыру в безопасности: >>> command = f'ls -l {shlex.quote(filename)}' >>> print(command) # ls -l 'somefile; rm -rf ~'
Разбор строки с командой bash/sh на отдельные команды:
>>> import shlex, pprint >>> cmd = '/bin/vikings -input eggs.txt -output "spam spam.txt" -cmd "echo \'$MONEY\'"' >>> args = shlex.split(cmd) >>> pprint.pprint(args, width='60') #['/bin/vikings', # '-input', # 'eggs.txt', # '-output', # 'spam spam.txt', # '-cmd', # "echo '$MONEY'"]