shlex --- Phân tích từ vựng đơn giản¶
Source code: Lib/shlex.py
Lớp shlex giúp bạn dễ dàng viết các bộ phân tích từ vựng cho các cú pháp đơn giản giống với cú pháp của shell Unix. Điều này thường hữu ích khi viết các ngôn ngữ nhỏ (ví dụ: trong các tệp điều khiển chạy cho ứng dụng Python) hoặc để phân tích các chuỗi được trích dẫn.
Mô-đun shlex xác định các chức năng sau:
- shlex.split(s, comments=False, posix=True)¶
Tách chuỗi s bằng cú pháp giống shell. Nếu comments là
False(mặc định), việc phân tích cú pháp nhận xét trong chuỗi đã cho sẽ bị tắt (đặt thuộc tínhcommenterscủa phiên bảnshlexthành chuỗi trống). Hàm này hoạt động ở chế độ POSIX theo mặc định, nhưng sử dụng chế độ không phải POSIX nếu đối số posix là sai.Thay đổi trong phiên bản 3.12: Việc chuyển
Nonecho đối số s hiện gây ra một ngoại lệ, thay vì đọcsys.stdin.
- shlex.join(split_command)¶
Ghép các mã thông báo của danh sách split_command và trả về một chuỗi. Hàm này là nghịch đảo của
split().>>> from shlex import join >>> print(join(['echo', '-n', 'Multiple words'])) echo -n 'Multiple words'
Giá trị được trả về là thoát shell để bảo vệ khỏi các lỗ hổng tiêm (xem
quote()).Added in version 3.8.
- shlex.quote(s)¶
Trả về phiên bản thoát shell của chuỗi s. Giá trị được trả về là một chuỗi có thể được sử dụng một cách an toàn dưới dạng một mã thông báo trong dòng lệnh shell, trong trường hợp bạn không thể sử dụng danh sách.
Cảnh báo
Mô-đun
shlexlà only designed for Unix shells.Chức năng
quote()không được đảm bảo là chính xác trên các hệ vỏ không tuân thủ POSIX hoặc các hệ vỏ từ các hệ điều hành khác như Windows. Việc thực thi các lệnh được mô-đun này trích dẫn trên các shell như vậy có thể mở ra khả năng xảy ra lỗ hổng chèn lệnh.Hãy cân nhắc việc sử dụng các hàm truyền đối số lệnh với các danh sách, chẳng hạn như
subprocess.run()vớishell=False.Thành ngữ này sẽ không an toàn:
>>> filename = 'somefile; rm -rf ~' >>> command = 'ls -l {}'.format(filename) >>> print(command) # executed by a shell: boom! ls -l somefile; rm -rf ~
quote()cho phép bạn cắm lỗ hổng bảo mật:>>> 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 ~'"'"''
Trích dẫn tương thích với shell UNIX và với
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 ~']
Added in version 3.3.
Mô-đun shlex định nghĩa lớp sau:
- class shlex.shlex(instream=None, infile=None, posix=False, punctuation_chars=False)¶
Một phiên bản
shlexhoặc phiên bản lớp con là một đối tượng phân tích từ vựng. Đối số khởi tạo, nếu có, chỉ định nơi đọc các ký tự. Nó phải là một đối tượng giống như tệp/luồng với các phương thứcread()vàreadline()hoặc một chuỗi. Nếu không có đối số nào được đưa ra, đầu vào sẽ được lấy từsys.stdin. Đối số tùy chọn thứ hai là chuỗi tên tệp, đặt giá trị ban đầu của thuộc tínhinfile. Nếu đối số instream bị bỏ qua hoặc bằngsys.stdin, đối số thứ hai này sẽ mặc định là "stdin". Đối số posix xác định chế độ hoạt động: khi posix không đúng (mặc định), phiên bảnshlexsẽ hoạt động ở chế độ tương thích. Khi hoạt động ở chế độ POSIX,shlexsẽ cố gắng bám sát nhất có thể các quy tắc phân tích cú pháp shell POSIX. Đối số punctuation_chars cung cấp một cách để làm cho hành vi thậm chí gần hơn với cách phân tích cú pháp của shell thực. Điều này có thể nhận một số giá trị: giá trị mặc định,False, duy trì hành vi được thấy trong Python 3.5 trở về trước. Nếu được đặt thànhTruethì việc phân tích cú pháp các ký tự();<>|&sẽ thay đổi: mọi lần chạy các ký tự này (được coi là ký tự dấu chấm câu) đều được trả về dưới dạng một mã thông báo. Nếu được đặt thành chuỗi ký tự không trống, các ký tự đó sẽ được sử dụng làm ký tự dấu chấm câu. Bất kỳ ký tự nào trong thuộc tínhwordcharsxuất hiện trong punctuation_chars sẽ bị xóa khỏiwordchars. Xem Cải thiện khả năng tương thích với Shell để biết thêm thông tin. punctuation_chars chỉ có thể được đặt khi tạo phiên bảnshlexvà không thể sửa đổi sau này.Thay đổi trong phiên bản 3.6: Tham số punctuation_chars đã được thêm vào.
Xem thêm
- Mô-đun
configparser Trình phân tích cú pháp cho các tệp cấu hình tương tự như tệp
.inicủa Windows.
đối tượng shlex¶
Một phiên bản shlex có các phương thức sau:
- shlex.get_token()¶
Trả lại một mã thông báo. Nếu mã thông báo đã được xếp chồng lên nhau bằng
push_token(), hãy lấy mã thông báo ra khỏi ngăn xếp. Nếu không, hãy đọc một từ luồng đầu vào. Nếu quá trình đọc gặp phần cuối tệp ngay lập tức,eofsẽ được trả về (chuỗi trống ('') ở chế độ không phải POSIX vàNoneở chế độ POSIX).
- shlex.push_token(str)¶
Đẩy đối số vào ngăn xếp mã thông báo.
- shlex.read_token()¶
Đọc mã thông báo thô. Bỏ qua ngăn xếp phản hồi và không diễn giải các yêu cầu nguồn. (Đây thường không phải là điểm đầu vào hữu ích và được ghi lại ở đây chỉ nhằm mục đích hoàn thiện.)
- shlex.sourcehook(filename)¶
Khi
shlexphát hiện một yêu cầu nguồn (xemsourcebên dưới), phương thức này được cung cấp mã thông báo sau làm đối số và dự kiến sẽ trả về một bộ dữ liệu bao gồm tên tệp và một đối tượng giống như tệp đang mở.Thông thường, phương pháp này trước tiên sẽ loại bỏ mọi trích dẫn khỏi đối số. Nếu kết quả là tên đường dẫn tuyệt đối hoặc không có yêu cầu nguồn nào trước đó có hiệu lực hoặc nguồn trước đó là một luồng (chẳng hạn như
sys.stdin) thì kết quả sẽ được giữ nguyên. Mặt khác, nếu kết quả là một tên đường dẫn tương đối, thì phần thư mục của tên tệp ngay trước nó trên ngăn xếp bao gồm nguồn sẽ được thêm vào trước (hành vi này giống như cách bộ tiền xử lý C xử lý#include "file.h").Kết quả của các thao tác được xử lý dưới dạng tên tệp và được trả về dưới dạng thành phần đầu tiên của bộ dữ liệu, với
open()được gọi để tạo ra thành phần thứ hai. (Lưu ý: đây là sự đảo ngược thứ tự của các đối số trong quá trình khởi tạo cá thể!)Móc này được hiển thị để bạn có thể sử dụng nó để triển khai các đường dẫn tìm kiếm thư mục, bổ sung các phần mở rộng tệp và các thủ thuật hack không gian tên khác. Không có hook 'đóng' tương ứng, nhưng một phiên bản shlex sẽ gọi phương thức
close()của luồng đầu vào có nguồn gốc khi nó trả về EOF.Để kiểm soát rõ ràng hơn việc xếp chồng nguồn, hãy sử dụng phương pháp
push_source()vàpop_source().
- shlex.push_source(newstream, newfile=None)¶
Đẩy luồng nguồn đầu vào vào ngăn xếp đầu vào. Nếu đối số tên tệp được chỉ định thì sau này nó sẽ có sẵn để sử dụng trong các thông báo lỗi. Đây là phương pháp tương tự được phương pháp
sourcehook()sử dụng nội bộ.
- shlex.pop_source()¶
Đưa nguồn đầu vào được đẩy lần cuối ra khỏi ngăn xếp đầu vào. Đây là phương pháp tương tự được sử dụng nội bộ khi lexer đạt EOF trên luồng đầu vào xếp chồng.
- shlex.error_leader(infile=None, lineno=None)¶
Phương pháp này tạo ra một thông báo lỗi dẫn đầu ở định dạng nhãn lỗi trình biên dịch Unix C; định dạng là
'"%s", line %d: ', trong đó%sđược thay thế bằng tên của tệp nguồn hiện tại và%dbằng số dòng đầu vào hiện tại (có thể sử dụng các đối số tùy chọn để ghi đè các đối số này).Sự tiện lợi này được cung cấp để khuyến khích người dùng
shlextạo thông báo lỗi ở định dạng tiêu chuẩn, có thể phân tích được mà Emacs và các công cụ Unix khác hiểu được.
Các phiên bản của lớp con shlex có một số biến phiên bản công khai kiểm soát phân tích từ vựng hoặc có thể được sử dụng để gỡ lỗi:
- shlex.commenters¶
Chuỗi ký tự được công nhận là người mới bắt đầu nhận xét. Tất cả các ký tự từ đầu bình luận đến cuối dòng đều bị bỏ qua. Theo mặc định chỉ bao gồm
'#'.
- shlex.wordchars¶
Chuỗi ký tự sẽ tích lũy thành mã thông báo nhiều ký tự. Theo mặc định, bao gồm tất cả các chữ số và dấu gạch dưới ASCII. Ở chế độ POSIX, các ký tự có dấu trong bộ Latin-1 cũng được bao gồm. Nếu
punctuation_charskhông trống, các ký tự~-./*?=, có thể xuất hiện trong thông số tên tệp và tham số dòng lệnh, cũng sẽ được bao gồm trong thuộc tính này và mọi ký tự xuất hiện trongpunctuation_charssẽ bị xóa khỏiwordcharsnếu chúng xuất hiện ở đó. Nếuwhitespace_splitđược đặt thànhTrue, điều này sẽ không có hiệu lực.
- shlex.whitespace¶
Các ký tự sẽ được coi là khoảng trắng và bị bỏ qua. Mã thông báo giới hạn khoảng trắng. Theo mặc định, bao gồm dấu cách, tab, nguồn cấp dữ liệu và trả về đầu dòng.
- shlex.escape¶
Những nhân vật sẽ được coi là trốn thoát. Điều này sẽ chỉ được sử dụng ở chế độ POSIX và chỉ bao gồm
'\'theo mặc định.
- shlex.quotes¶
Các ký tự sẽ được coi là dấu ngoặc kép. Mã thông báo sẽ tích lũy cho đến khi gặp lại cùng một trích dẫn (do đó, các loại trích dẫn khác nhau sẽ bảo vệ lẫn nhau như trong shell.) Theo mặc định, bao gồm dấu ngoặc đơn và dấu ngoặc kép ASCII.
- shlex.escapedquotes¶
Các ký tự trong
quotessẽ diễn giải các ký tự thoát được xác định trongescape. Điều này chỉ được sử dụng ở chế độ POSIX và chỉ bao gồm'"'theo mặc định.
- shlex.whitespace_split¶
Nếu
True, mã thông báo sẽ chỉ được chia thành khoảng trắng. Điều này rất hữu ích, chẳng hạn như để phân tích các dòng lệnh bằngshlex, nhận mã thông báo theo cách tương tự như các đối số shell. Khi được sử dụng kết hợp vớipunctuation_chars, mã thông báo sẽ được phân chia trên khoảng trắng ngoài các ký tự đó.Thay đổi trong phiên bản 3.8: Thuộc tính
punctuation_charsđã được làm tương thích với thuộc tínhwhitespace_split.
- shlex.infile¶
Tên của tệp đầu vào hiện tại, như được đặt ban đầu tại thời điểm khởi tạo lớp hoặc được xếp chồng lên nhau theo các yêu cầu nguồn sau này. Có thể hữu ích khi kiểm tra điều này khi xây dựng các thông báo lỗi.
- shlex.source¶
Thuộc tính này mặc định là
None. Nếu bạn gán một chuỗi cho nó, chuỗi đó sẽ được nhận dạng là yêu cầu đưa vào cấp độ từ vựng tương tự như từ khóasourcetrong các shell khác nhau. Nghĩa là, mã thông báo ngay sau đó sẽ được mở dưới dạng tên tệp và đầu vào sẽ được lấy từ luồng đó cho đến EOF, tại thời điểm đó, phương thứcclose()của luồng đó sẽ được gọi và nguồn đầu vào sẽ lại trở thành luồng đầu vào ban đầu. Yêu cầu nguồn có thể được xếp chồng lên nhau ở bất kỳ cấp độ sâu nào.
- shlex.debug¶
Nếu thuộc tính này là số và
1trở lên, phiên bảnshlexsẽ in kết quả tiến trình chi tiết về hành vi của nó. Nếu cần sử dụng, bạn có thể đọc mã nguồn mô-đun để tìm hiểu chi tiết.
- shlex.lineno¶
Số dòng nguồn (số dòng mới được thấy cho đến nay cộng với một).
- shlex.token¶
Bộ đệm mã thông báo. Có thể hữu ích khi kiểm tra điều này khi phát hiện các ngoại lệ.
- shlex.eof¶
Mã thông báo được sử dụng để xác định phần cuối của tệp. Điều này sẽ được đặt thành chuỗi trống (
''), ở chế độ không phải POSIX và thànhNoneở chế độ POSIX.
- shlex.punctuation_chars¶
Thuộc tính chỉ đọc. Các ký tự sẽ được coi là dấu câu. Các chuỗi ký tự dấu chấm câu sẽ được trả về dưới dạng một mã thông báo duy nhất. Tuy nhiên, lưu ý rằng việc kiểm tra tính hợp lệ ngữ nghĩa sẽ không được thực hiện: ví dụ: '>>>' có thể được trả về dưới dạng mã thông báo, mặc dù nó có thể không được shell nhận dạng như vậy.
Added in version 3.6.
Quy tắc phân tích cú pháp¶
Khi hoạt động ở chế độ không phải POSIX, shlex sẽ cố gắng tuân theo các quy tắc sau.
Các ký tự trích dẫn không được nhận dạng trong các từ (
Do"Not"Separateđược phân tích cú pháp dưới dạng một từDo"Not"Separate);Ký tự thoát không được nhận dạng;
Việc đặt các ký tự trong dấu ngoặc kép sẽ giữ nguyên giá trị nguyên văn của tất cả các ký tự trong dấu ngoặc kép;
Kết thúc dấu ngoặc kép các từ riêng biệt (
"Do"Separateđược phân tích thành"Do"vàSeparate);Nếu
whitespace_splitlàFalse, bất kỳ ký tự nào không được khai báo là ký tự Word, khoảng trắng hoặc trích dẫn sẽ được trả về dưới dạng mã thông báo một ký tự. Nếu làTrue,shlexsẽ chỉ chia các từ trong khoảng trắng;EOF được báo hiệu bằng một chuỗi trống (
'');Không thể phân tích các chuỗi trống, ngay cả khi được trích dẫn.
Khi hoạt động ở chế độ POSIX, shlex sẽ cố gắng tuân theo các quy tắc phân tích cú pháp sau.
Các trích dẫn được loại bỏ và không phân tách các từ (
"Do"Not"Separate"được phân tích cú pháp thành một từ duy nhấtDoNotSeparate);Các ký tự thoát không được trích dẫn (ví dụ:
'\') giữ nguyên giá trị bằng chữ của ký tự tiếp theo theo sau;Việc đặt các ký tự trong dấu ngoặc kép không phải là một phần của
escapedquotes(ví dụ:"'") sẽ giữ nguyên giá trị bằng chữ của tất cả các ký tự trong dấu ngoặc kép;Việc đặt các ký tự trong dấu ngoặc kép là một phần của
escapedquotes(ví dụ:'"') sẽ giữ nguyên giá trị nguyên văn của tất cả các ký tự trong dấu ngoặc kép, ngoại trừ các ký tự được đề cập trongescape. Các ký tự thoát chỉ giữ lại ý nghĩa đặc biệt của chúng khi theo sau là dấu ngoặc kép được sử dụng hoặc chính ký tự thoát. Ngược lại ký tự thoát sẽ được coi là ký tự bình thường.EOF được báo hiệu bằng giá trị
None;Cho phép các chuỗi trống được trích dẫn (
'').
Cải thiện khả năng tương thích với Shell¶
Added in version 3.6.
Lớp shlex cung cấp khả năng tương thích với việc phân tích cú pháp được thực hiện bởi các shell Unix phổ biến như bash, dash và sh. Để tận dụng khả năng tương thích này, hãy chỉ định đối số punctuation_chars trong hàm tạo. Giá trị mặc định này là False, duy trì hành vi trước 3.6. Tuy nhiên, nếu nó được đặt thành True thì việc phân tích cú pháp các ký tự ();<>|& sẽ thay đổi: mọi lần chạy các ký tự này đều được trả về dưới dạng một mã thông báo duy nhất. Mặc dù đây không phải là một trình phân tích cú pháp đầy đủ cho các shell (sẽ nằm ngoài phạm vi của thư viện tiêu chuẩn, do có rất nhiều shell), nhưng nó cho phép bạn thực hiện xử lý các dòng lệnh dễ dàng hơn những gì bạn có thể làm. Để minh họa, bạn có thể thấy sự khác biệt trong đoạn trích sau:
>>> nhập shlex
>>> text = "a && b; c && d || e; f >'abc'; (def \"ghi\")"
>>> s = shlex.shlex(văn bản, posix=True)
>>> s.whitespace_split = Đúng
>>> danh sách
['a', '&&', 'b;', 'c', '&&', 'd', '||', 'e;', 'f', '>abc;', '(def', 'ghi)']
>>> s = shlex.shlex(văn bản, posix=True, punctuation_chars=True)
>>> s.whitespace_split = Đúng
>>> danh sách
['a', '&&', 'b', ';', 'c', '&&', 'd', '||', 'e', ';', 'f', '>', 'abc', ';',
'(', 'def', 'ghi', ')']
Tất nhiên, các mã thông báo sẽ được trả về không hợp lệ đối với hệ vỏ và bạn sẽ cần thực hiện kiểm tra lỗi của riêng mình đối với các mã thông báo được trả về.
Thay vì chuyển True làm giá trị cho tham số punctuation_chars, bạn có thể chuyển một chuỗi có các ký tự cụ thể sẽ được sử dụng để xác định ký tự nào cấu thành dấu câu. Ví dụ:
>>> nhập shlex
>>> s = shlex.shlex("a && b || c", punctuation_chars="|")
>>> danh sách
['a', '&', '&', 'b', '||', 'c']
Ghi chú
Khi punctuation_chars được chỉ định, thuộc tính wordchars được tăng thêm các ký tự ~-./*?=. Đó là vì những ký tự này có thể xuất hiện trong tên tệp (bao gồm ký tự đại diện) và đối số dòng lệnh (ví dụ: --color=auto). Do đó:
>>> nhập shlex
>>> s = shlex.shlex('~/a && b-c --color=auto || d *.py?',
... punctuation_chars=True)
>>> danh sách
['~/a', '&&', 'b-c', '--color=auto', '||', 'd', '*.py?']
Tuy nhiên, để khớp với shell nhất có thể, bạn nên luôn sử dụng posix và whitespace_split khi sử dụng punctuation_chars, điều này sẽ phủ nhận hoàn toàn wordchars.
Để có hiệu quả tốt nhất, punctuation_chars nên được đặt cùng với posix=True. (Lưu ý rằng posix=False là mặc định cho shlex.)