Làm cách nào tôi có thể ngăn chặn việc mở rộng Bash chuyển các tệp bắt đầu bằng đối số - - làm đối số?


14

Tôi đang cố gắng tìm kiếm đệ quy một chuỗi grepnhưng tôi nhận được điều này:

$ grep -r "stuff" *
grep: unrecognized option '---corporate-discount.csv'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.

Làm cách nào tôi có thể ngăn Bash chuyển các tệp bắt đầu bằng -đối số?



3
Bạn không thực sự muốn ngăn shell chuyển các tập tin này, phải không? Câu hỏi là làm thế nào để nói greprằng họ không có lựa chọn.
DonHolgo

11
... Để rõ ràng, bash không kiểm soát kết quả nào được coi là tùy chọn so với đối xử; đó là trong sự kiểm soát của chương trình nhận. Bạn sẽ có hành vi tương tự với, giả sử, subprocess.Popen(['grep', '-r', '-e' 'stuff', '--corporate-discount.csv'])trong Python, không có bash ở bất cứ đâu.
Charles Duffy

1
Đọc liên quan: Unix Wildcards Gone Wild , về các vấn đề bảo mật có thể gây ra bằng cách sử dụng *trong các lệnh. TẤT CẢ những điều này có thể tránh được bằng cách sử dụng ./*thay thế.
tự đại diện

1
@Wildcard, sử dụng --như một sigil cuối tùy chọn là hoàn toàn hợp lý là tốt; Hướng dẫn cú pháp tiện ích POSIX yêu cầu nó phải được tôn vinh; xem hướng dẫn # 10. (Chắc chắn, không phải tất cả các chương trình đều tuân theo hướng dẫn POSIX, nhưng câu trả lời là xâu chuỗi các tác giả của chương trình vi phạm và / hoặc đẩy họ ra khỏi ngành).
Charles Duffy

Câu trả lời:


43

Đầu tiên, lưu ý rằng việc giải thích các đối số bắt đầu bằng dấu gạch ngang tùy thuộc vào chương trình được bắt đầu grephoặc khác. Vỏ không có cách trực tiếp để kiểm soát nó.

Giả sử bạn muốn xử lý các tệp như vậy (và không bỏ qua chúng hoàn toàn) grep, cùng với hầu hết các chương trình, nhận ra --là chỉ ra kết thúc của các tùy chọn, vì vậy

grep -r -e "stuff" -- *

sẽ làm những gì bạn muốn. Có -etrong trường hợp stuffbắt đầu với một -là tốt.

Ngoài ra, bạn cũng có thể sử dụng:

grep -r -e "stuff"  ./*

Cái sau này cũng sẽ tránh được vấn đề nếu có một tệp được gọi -trong thư mục hiện tại. Ngay cả sau --dấu phân cách, grepdiễn giải -là stdin có nghĩa ./-là tệp được gọi -trong thư mục hiện tại.


8

Để ngăn chặn việc mở rộng Bash chuyển các tập tin bắt đầu bằng từ - Bạn có thể sử dụng:

echo [!-]*

Mà hoạt động có thể di chuyển trong hầu hết các shell, hoặc, cụ thể cho ksh, bash, zsh:

echo !(-*)

Ví dụ: trong một thư mục chứa các tệp này

$ echo *
a b c ---corporate-discount.csv d -e --option.txt

Sẽ chỉ liệt kê (được cung cấp extgloblà hoạt động):

$ shopt -s extglob
$ echo !(-*)
a b c d

$ echo [!-]*
a b c d

Nhưng nếu điều bạn muốn là xử lý tất cả các tệp trong khi nói với grep để tránh diễn giải các tệp được nêu với -tùy chọn dưới dạng, thì chỉ cần thêm ./:

grep -r "stuff" ./*

Hoặc, nếu có đảm bảo rằng không có tệp nào được gọi chính xác -tồn tại trong các tệp được liệt kê (grep sẽ diễn giải sự cô đơn -khi đọc từ stdin ), bạn có thể sử dụng:

grep -r -- "stuff" *

Có, như câu hỏi là về bash, shell GNU, có vẻ hợp lý khi cho rằng GNU grep có sẵn, có thể được cài đặt hoặc thực sự đang được sử dụng. @ StéphaneChazelas
Isaac

Có, a grep -r -- stuff *đơn giản hơn và cũng hoạt động với các greps không GNU. Vì vậy: thêm, cảm ơn. @ StéphaneChazelas
Isaac

@Isaac Tôi sẽ không nói đó là một giả định hợp lý "nếu có sẵn bash, GNU grep cũng có sẵn". Ví dụ FreeBSD: bash không được cài đặt theo mặc định , có thể được cài đặt sau, nhưng không có tác dụng với grep - đó vẫn là phiên bản BSD của grep trừ khi GNU grep được cài đặt rõ ràng. Nhưng đó là một cú đánh nhỏ. Tôi thích cách tiếp cận thay thế thông qua extglob, do đó + 1 câu trả lời
Sergiy Kolodyazhnyy

2
@SergiyKolodyazhnyy, AFAIK, greptrên FreeBSD vẫn dựa trên GNU grepvà vẫn có sự không thỏa đáng đó theo đó các tùy chọn được nhận ra sau khi không có tùy chọn. Ngay cả các BSD như OpenBSD đã viết lại chúng cũng grepkhiến chúng tương thích với GNU về tính di động lạc hậu (và vẫn thể hiện hành vi đó ở đây). Trên macOS, sh là bash, nhưng tôi mong grep của họ không thể hiện hành vi đó vì macOS có nghĩa là tuân thủ POSIX ngay cả khi không có $ POSIXLY_CORRECT. Trong mọi trường hợp, grep của OP GNU tương thích vì nó mang lại cho lỗi đó.
Stéphane Chazelas

1
Xem thêm echo [!-]*như một tiêu chuẩn tương đương với ksh's (hoặc bash -O extglob') echo !(-*).
Stéphane Chazelas
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.