Dừng mở rộng ký tự đại diện shell?


88

Có cách nào để một chương trình dòng lệnh đã biên dịch nói với bash hoặc csh rằng nó không muốn bất kỳ ký tự đại diện nào trong các tham số của nó được mở rộng không?

Ví dụ, một người có thể muốn một lệnh shell như:

foo *

để chỉ cần trả về giá trị ASCII dạng số của ký tự đó.

Câu trả lời:


117

Không. Việc mở rộng diễn ra trước khi lệnh thực sự được chạy.
Bạn chỉ có thể vô hiệu hóa hình cầu trước khi chạy lệnh hoặc bằng cách trích dẫn dấu sao.

$ # quote it
$ foo '*'

$ # or escape it
$ foo \*

$ # or disable the glob (noglob)
$ set -f
$ foo *

$ # alternative to set -f
$ set -o noglob
$ # undo it by 
$ set +o noglob

3
cũng vậy, nếu không có gì để mở rộng, thì không có sự mở rộng. tức là với một sản phẩm nào pwd, echo *chỉ là*
sam boosalis

7
@sam Điều này thực sự phụ thuộc vào cách các tùy chọn của bạn được thiết lập. Từ tldp: "Nếu không tìm thấy tên tệp phù hợp nào và tùy chọn trình bao nullglobbị tắt, từ đó sẽ không thay đổi. Nếu nullglobtùy chọn được đặt và không tìm thấy kết quả phù hợp nào, từ đó sẽ bị xóa."
Chris Middleton

cảm ơn, tôi nên đủ điều kiện rằng đó chỉ là từ quan sát không từ bất kỳ hiểu biết.
sam boosalis

@ c00kiemon5ter Làm thế nào để hoàn tác set -f? Là nó unset -f?
Nam G VU

1
@NamGVUset +f
Yngvar Kristiansen

62

Mặc dù đúng là bản thân một lệnh không thể tắt chế độ hiển thị, nhưng người dùng có thể yêu cầu trình bao Unix không ngắt lệnh cụ thể. Điều này thường được thực hiện bằng cách chỉnh sửa các tệp cấu hình của trình bao. Giả sử lệnh foocó thể được tìm thấy dọc theo đường dẫn lệnh, bạn cần thêm thông tin sau vào tệp cấu hình thích hợp:

Đối với shell sh, bash và ksh:

alias foo='set -f;foo';foo(){ command foo "$@";set +f;}

Đối với shell csh và tcsh:

alias foo 'set noglob;\foo \!*;unset noglob'

Đối với trình bao zsh:

alias foo='noglob foo'

Đường dẫn lệnh không cần phải được sử dụng. Giả sử lệnh foo được lưu trữ trong thư mục ~ / bin, thì ở trên sẽ trở thành:

Đối với shell sh, bash và ksh:

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

Đối với shell csh và tcsh:

alias foo 'set noglob;$home/bin/foo \!*;unset noglob'

Đối với trình bao zsh:

alias foo='noglob ~/bin/foo'

Tất cả những điều trên đã được thử nghiệm bằng OSX 10.9.2 của Apple. Lưu ý: Khi sao chép đoạn mã trên, hãy cẩn thận về việc xóa bất kỳ khoảng trắng nào. Chúng có thể đáng kể.

Cập nhật:

Người dùng geira đã chỉ ra rằng trong trường hợp bash shell

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

có thể được thay thế bằng

reset_expansion(){ CMD="$1";shift;$CMD "$@";set +f;}
alias foo='set -f;reset_expansion ~/bin/foo'

điều này giúp loại bỏ sự cần thiết của hàm foo.

Một số trang web được sử dụng để tạo tài liệu này:


3
Đây lẽ ra phải là câu trả lời được chấp nhận vì nó chứng tỏ rằng OP thực sự có thể làm được những gì OP muốn. Đối với một số phương pháp thậm chí còn tốt hơn trong bash, liên kết này ghi lại các tùy chọn khác nhau: blog.edwards-research.com/2011/05/preventing-globbing
geira

@geira: Đôi khi câu trả lời được chấp nhận trước khi câu trả lời tốt hơn được đăng. Tôi tin rằng đây có thể là một trong những trường hợp đó. Tôi cũng tin rằng câu trả lời đánh dấu là hữu ích nhất bởi người dùng sẽ kết thúc trước tiên. Lưu ý: Tôi đã thêm đầu vào của bạn vào câu trả lời của tôi.
David Anderson

@geira, OP muốn chương trình đã biên dịch giao tiếp với shell; trả lời rằng có thể định cấu hình trình bao hoạt động như mong muốn trên cơ sở từng lệnh là một câu trả lời hữu ích và bản thân tôi cũng sẽ chấp nhận câu trả lời này, nhưng tôi thấy có chỗ để không đồng ý về việc liệu nó có hoàn toàn đúng lúc hay không.
Charles Duffy

Thực tế là nó có thể được thực hiện không có nghĩa là nó nên được thực hiện. Việc hành vi của shell thay đổi so với kỳ vọng hợp lý của người dùng đối với các lệnh được chọn nghe có vẻ đáng ngạc nhiên và cuối cùng là không mong muốn.
tripleee

@tripleee: Đã có lúc người ta trông đợi vào rơ le và ống chân không. Dự kiến ​​là các lỗ được đục trên thẻ các tông và băng giấy. Mọi người tổ chức các quy tắc trượt thay vì máy tính và điện thoại. Tôi cho rằng đối với bạn điều này sẽ là mong muốn. Tôi không quan tâm lắm đến những lúc đó. Tôi rất thích xem những gì tiếp theo.
David Anderson,

8

Việc mở rộng được thực hiện bởi trình bao trước khi chương trình của bạn được chạy. Chương trình của bạn không có manh mối nào về việc mở rộng đã xảy ra hay chưa.

   set -o noglob

sẽ tắt mở rộng trong trình bao gọi, nhưng bạn phải làm điều đó trước khi gọi chương trình của mình.

Cách thay thế là trích dẫn các lập luận của bạn, ví dụ:

foo "*"

4
setopt dường như là lệnh dành riêng cho zsh. Như một người đăng khác đã nói, đối với bash, bạn sử dụng set -o noglobđể tắt mở rộng ký tự đại diện.
Wirawan Purwanto

Hiện đã được sửa đổi. Cảm ơn bạn
Brian Agnew

1

Hãy lưu ý: nếu không có tên nào phù hợp với mặt nạ, bash sẽ chuyển đối số nguyên trạng, không mở rộng!

Proof (pa.py là một tập lệnh rất đơn giản, chỉ in các đối số của nó):

 $ ls
f1.cc  f2.cc  pa.py
 $ ./pa.py *.cc
['./pa.py', 'f1.cc', 'f2.cc']
 $ ./pa.py *.cpp
['./pa.py', '*.cpp']

3
Không phải luôn luôn. set -o nullglobhoặc shopt -s failglob, và hành vi này sẽ thay đổi (theo hai cách rất khác nhau).
Charles Duffy
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.