Tách từ là gì? Tại sao nó quan trọng trong lập trình shell?


16

Tôi đang bối rối về vai trò chia tách vai trò trong zsh. Tôi chưa được tiếp xúc với khái niệm này khi lập trình bằng C, Python hoặc MATLAB và điều này đã kích thích sự quan tâm của tôi về lý do tại sao việc tách từ dường như là một cái gì đó cụ thể đối với lập trình shell.

Tôi đã đọc về việc chia từ trên trang này và các trang khác trước đây, nhưng chưa tìm thấy lời giải thích rõ ràng về khái niệm này. Wikipedia có định nghĩa về phân tách từ nhưng dường như không có tài liệu tham khảo về cách áp dụng cho hệ vỏ Unix.

Đây là một ví dụ về sự nhầm lẫn của tôi trong zsh:

Trong Câu hỏi thường gặp về Z Shell , tôi đọc phần sau:

3.1: Tại sao $varở đâu var="foo bar"không làm những gì tôi mong đợi?

Trong hầu hết các dẫn xuất shell Bourne, các biến nhiều từ như var="foo bar" được chia thành các từ khi được truyền cho một lệnh hoặc được sử dụng trong một for foo in $varvòng lặp. Theo mặc định, zsh không có hành vi đó: biến vẫn còn nguyên. (Đây không phải là một lỗi! Xem bên dưới.) Tùy chọn SH_WORD_SPLITtồn tại để cung cấp khả năng tương thích.

Tuy nhiên, trong Hướng dẫn sử dụng Z Shell , tôi đọc phần sau:

SH_WORD_SPLIT (-y) <K> <S>

Nguyên nhân phân tách trường được thực hiện trên các mở rộng tham số không được trích dẫn. Lưu ý rằng tùy chọn này không liên quan gì đến việc tách từ. (Xem Mở rộng tham số.)

Tại sao nó lại nói rằng SH_WORD_SPLITgì để làm với tách từ? Không phải là chia tách chính xác những gì này là tất cả về?

Câu trả lời:


21

Shell ban đầu chỉ có một kiểu dữ liệu duy nhất: chuỗi. Nhưng thông thường để thao tác danh sách các chuỗi, thông thường khi chuyển nhiều tên tệp làm đối số cho một chương trình. Một trường hợp sử dụng phổ biến khác để phân tách là khi một lệnh đưa ra một danh sách kết quả: đầu ra của lệnh là một chuỗi, nhưng dữ liệu mong muốn là một danh sách các chuỗi. Để lưu trữ danh sách tên tệp trong một biến, bạn sẽ đặt khoảng trắng giữa chúng. Sau đó, một kịch bản shell như thế này

files="foo bar qux"
myprogram $files

được gọi myprogramvới ba đối số, vì shell chia chuỗi $filesthành các từ. Vào thời điểm đó, khoảng trắng trong tên tệp bị cấm hoặc được coi là Không hoàn thành.

Các Korn shell giới thiệu mảng: bạn có thể lưu trữ một danh sách các chuỗi trong một biến. Lớp vỏ Korn vẫn tương thích với lớp vỏ Bourne được thiết lập sau đó, vì vậy việc mở rộng biến trần tiếp tục trải qua quá trình phân tách từ và sử dụng mảng đòi hỏi một số chi phí cú pháp. Bạn sẽ viết đoạn trích ở trên

files=(foo bar qux)
myprogram "${files[@]}"

Zsh đã có các mảng từ đầu và tác giả của nó đã chọn một thiết kế ngôn ngữ saner với chi phí tương thích ngược. Trong zsh (theo quy tắc mở rộng mặc định) $varkhông phân tách từ; nếu bạn muốn lưu trữ một danh sách các từ trong một biến, bạn có nghĩa là sử dụng một mảng; và nếu bạn thực sự muốn tách từ, bạn có thể viết $=var.

files=(foo bar qux)
myprogram $files

Ngày nay, không gian trong tên tệp là thứ bạn cần đối phó, bởi vì nhiều người dùng mong đợi chúng hoạt động và vì nhiều tập lệnh được thực thi trong bối cảnh nhạy cảm bảo mật nơi kẻ tấn công có thể kiểm soát tên tệp. Vì vậy, việc tách từ tự động thường gây phiền toái; do đó lời khuyên chung của tôi là luôn luôn sử dụng dấu ngoặc kép, tức là viết "$foo", trừ khi bạn hiểu lý do tại sao bạn cần tách từ trong trường hợp sử dụng cụ thể. (Lưu ý rằng việc mở rộng biến trần cũng trải qua quá trình toàn cầu hóa.)


Cảm ơn Gilles, điều này thực sự hữu ích! Có đúng không khi nói rằng việc chia từ nói đại khái sẽ chuyển đổi các chuỗi của biểu mẫu "word1 word2 word3"thành các danh sách / mảng của biểu mẫu "word1" "word2" "word3"? Tôi cũng đã cập nhật OP với một nguồn gây nhầm lẫn cụ thể trong zsh.
Amelio Vazquez-Reina

1
@intrpc "Chia tách từ" không phải là phân tách trên các từ ngôn ngữ tự nhiên mà là các $IFSký tự. Do đó "tách trường" là một tên tốt hơn. Nhưng "tách từ" thường được sử dụng cho khái niệm này trong tài liệu vỏ. Các tài liệu zsh đang ngụy biện cho các từ.
Gilles 'SO- ngừng trở nên xấu xa'

1
Xem thêm rc(shell plan9, cũng được chuyển sang Unix) để có thiết kế thậm chí còn tốt hơn zsh khi nói đến các biến và mảng.
Stéphane Chazelas

3

Chia tách từ không thực sự cụ thể.

Hầu hết các chương trình cần phân tích cú pháp nhập văn bản sử dụng một số hình thức phân tách từ làm bước đầu tiên. Nó được thực hiện trước khi xác định từ các "từ" này, số, toán tử, chuỗi, mã thông báo và bất kỳ thực thể tương tự nào chúng cần xử lý.

Điều đặc biệt với các shell là chúng phải xây dựng chính xác danh sách đối số của các lệnh được gọi là (C argc / argv, python sys.argv), bao gồm chuyển các đối số với khoảng trắng được nhúng, đối số trống, dấu phân cách tùy chỉnh, v.v. Nhiều shell sử dụng biến IFS để cho phép một số linh hoạt ở đó.


3

Trong trường hợp cụ thể này của Zsh, chia tách từ được định nghĩa hơi khác so với tách trường.

Hãy xem xét prog a b c, nó sẽ vượt qua trong ba đối số cho dù bạn đặt như thế nào IFS. Đây là từ tách.

Nếu bạn làm như vậy A="a b c"; prog $A, nó sẽ chuyển qua ba đối số nếu IFSbao gồm khoảng trắng hoặc một đối số khác. Đây là trường tách.

Định nghĩa ở đây là tinh tế. Điều mà tài liệu Zsh đang cố gắng nói là, ngay cả khi bạn tắt tùy chọn đó, prog a b cvẫn sẽ nhận được các đối số riêng biệt (đó là điều mọi người luôn mong đợi).


1
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.