2015-07-14 13 views
7

Tôi đã học được rằng các mở rộng tên tệp được thực hiện trước khi thực hiện lệnh khi chạy lệnh trong Bash. Nhưng khi thử các lệnh bên dưới (với tùy chọn -x):Mở rộng tên tệp trong các đối số "a = b" giống như các lệnh dựng sẵn Bash

touch foo=3 # Create a file with name "foo=3" 
+ touch foo=3 
declare foo=? 
+ declare 'foo=?' 
alias foo=* 
+ alias 'foo=*' 

Tôi không hiểu những gì tôi mong đợi vì foo =? và foo = * không được mở rộng đến các filename "foo = 3":

declare -p | grep 'foo=' # => foo='?' 
alias | grep 'foo='   # => alias foo='*' 

Nhưng nếu tôi chạy một built-in như cd hoặc một chức năng tiếp nhận chuyển nhượng như một tham số được viết bởi bản thân mình như show_rhs() { echo "${1%=*}='${1#*=}'"; } tôi được những gì tôi mong đợi (foo =? và foo = * được mở rộng).

cd foo=?   # => foo=3: Not a directory 
show_rhs() foo=* # => foo='3' 

Sự khác biệt duy nhất tôi có thể nhìn thấy ở đây là tuyên bố và bí danh là built-in chấp nhận chuyển nhượng như một tham số. Có vẻ như một cặp trích dẫn được thêm vào để bao gồm việc gán trước khi mở rộng tên tệp theo đầu ra của tùy chọn -x.

Nhưng nếu mở rộng tên tệp không chạy trước khi thực hiện lệnh bất kể lệnh là gì, đối số được chuyển vào khai báo và bí danh phải là foo = 3 thay vì foo =? và foo = * do sự hiện diện của tệp "foo = 3".

Vì vậy, Bash làm điều gì đó đặc biệt (có thể trích dẫn các ký tự đại diện?) Cho các đối số như "a = b" phụ thuộc vào các lệnh trước khi mở rộng tên tệp?

(môi trường của tôi: CentOS 5.8 64bit, GNU Bash 3.2.25)

+0

Bí danh và biến tồn tại ở các không gian tên khác nhau. Bạn hoàn toàn có thể có một bí danh và một biến có cùng tên.Một biến được tạo với một phép gán đơn giản và một biến được tạo ra với 'khai báo' là cùng một điều mặc dù vậy' foo = 3; khai báo foo =? 'để bạn biến' foo' với giá trị '?'. Bạn có chắc chắn bạn nhận được các lỗi mà bạn yêu cầu cho hai dòng cuối cùng không? Bởi vì tôi không thấy làm thế nào có thể. Cả hai bối cảnh đó sẽ không đánh giá các biến (và thứ hai không phải là một dòng shell hợp lệ và sẽ cho bạn một lỗi về một mã thông báo không mong muốn). –

+0

Xin lỗi vì sự nhầm lẫn. Tôi không có nghĩa là nếu có thể tạo một biến và bí danh có cùng tên. Tôi có nghĩa là cả hai foo =? và foo = * nên được mở rộng thành foo = 3 do sự hiện diện của tệp "foo = 3" trước khi được chuyển vào các lệnh đó, vì vậy cả biến và bí danh được cho là có giá trị "3" thay vì gốc ký tự đại diện. Mã khai báo và bí danh chỉ là các ví dụ. – ebk

+0

Ah, ok. Tôi gần như nhận xét về một tập tin 'foo = 3' nhưng nghĩ rằng đó là không (và bạn đã không đề cập đến trong bài viết). Nhưng có, tôi nghĩ rằng đoán của bạn có thể là chính xác. Thực tế là những người được xây dựng trong chấp nhận các bài tập trực tiếp có nghĩa là hành vi mở rộng glob bình thường khác không xảy ra ở đó. (Nó cũng không xảy ra với 'foo =?'.) Có lẽ có gì đó trong thông số POSIX về điều này. Tôi có thể thử nhìn sau. –

Trả lời

2

Bash phân tích một số lệnh built-in của nó theo một cách mà không phải là nghiêm Posix tuân thủ, và cũng không phải là rất tốt tài liệu.

Đặc biệt, đối số nhiệm vụ trong lệnh mà chấp nhận lập luận như vậy (alias, declare, export, local, readonlytypeset) không thuộc đối tượng tên đường dẫn mở rộng cũng không từ tách. (Điều này được thực hiện trong nội bộ bằng cách diệt mở rộng, không phải bằng cách trích dẫn các metacharacters, mặc dù nó không phải dễ dàng để xem cách chi tiết thi hành có thể trở thành có thể nhìn thấy.)

Điều này xảy ra ngay cả khi bash được bắt đầu trong chế độ Posix hoặc như sh.

Lưu ý rằng việc triệt tiêu mở rộng tên đường chỉ áp dụng cho các đối số giống như các bài tập. Mở rộng ví dụ từ câu hỏi:

touch foo=3 # Create a file with name "foo=3" 
+ touch foo=3 
declare foo=? 
+ declare 'foo=?' 

bar="foo=?" # Put the declare argument in a variable 
+ bar='foo=?' 
declare $bar 
+ declare foo=3 

Đúng như dự đoán, dash tên đường dẫn mở rộng và word-chia đối số cho aliasexport, phù hợp với spec Posix. Vì vậy, rõ ràng, không zsh.

Ngoại trừ ở chế độ Posix, bash cũng dấu ngã-mở rộng phía bên phải của đối số giống như bài tập. Trong chế độ Posix, nó hạn chế điều này đối với các đối số gán của các nội trang được liệt kê ở trên, mặc dù Posix chỉ định mở rộng dấu ngã sau = chỉ trong các phép gán thay đổi trước từ lệnh. Đó là những gì dash thực hiện, nhưng zsh mở rộng điều này thành "lệnh của họ nhóm" (được ghi trong zsh manual).

+0

@ebk: trang bạn trích dẫn rõ ràng nói rằng các bài tập biến "đến trước tên lệnh", đó cũng là những gì tôi đã nói đến. (Điều này bao gồm các bài tập không có từ lệnh.) – rici

+0

Xin lỗi, tôi đã vô tình xóa nhận xét trước đó của mình vì tôi chưa quen với stackoverflow. Chỉ cần đăng [liên kết trang] (http://www.gnu.org/software/bash/manual/html_node/Simple-Command-Expansion.html) một lần nữa làm tài liệu tham khảo cho người khác. Tôi chỉ không thể hình dung làm thế nào để đặt một nhiệm vụ biến trước khi một tên lệnh trong một lệnh đơn giản, ngoại trừ các bài tập mà không có một từ lệnh. Ông có thể cho tôi một ví dụ? – ebk

+2

@ebk: Nếu bạn đặt một nhiệm vụ trước từ lệnh, nhiệm vụ chỉ áp dụng cho môi trường được truyền cho lệnh. Ví dụ phổ biến nhất có lẽ là 'IFS =, read -r a b c', trong đó gán cho' IFS' không hiển thị trong kịch bản, nhưng là một phần của môi trường được sử dụng bởi lệnh 'read'. Có một lời giải thích dài hơn với các ví dụ trong lớp vỏ kịch bản lệnh shell của Apple, https://developer.apple.com/library/mac/documentation/OpenSource/Conceptual/ShellScripting/shell_scripts/shell_scripts.html#//apple_ref/doc/uid/TP40004268 -CH237-SW12 – rici

Các vấn đề liên quan