(Các) sự cố biểu thức chính quy trong Bash: [^ negate] dường như không hoạt động


8

Khi tôi thực thi ls /directory | grep '[^term]'trong Bash tôi nhận được một danh sách thông thường, như thể greplệnh bị bỏ qua bằng cách nào đó. Tôi đã thử điều tương tự với egrep, tôi đã thử sử dụng nó với dấu ngoặc kép và dấu ngoặc đơn, nhưng không có kết quả tốt hơn. Khi tôi thử, ls /directory | grep '^[term]tôi nhận được tất cả các mục bắt đầu bằng thuật ngữ - như mong đợi.

Tôi đã thử lệnh này trong một trình soạn thảo trực tuyến, nơi tôi có thể kiểm tra regex của mình và nó hoạt động như bình thường. Nhưng không phải ở Bash. Vì vậy, nó hoạt động trong một mô phỏng, nhưng không phải trong cuộc sống thực.

Tôi làm việc trên Crunchbang Linux 10. Tôi hy vọng đây là đủ thông tin và đang mong chờ mọi gợi ý, bởi vì việc không thực hiện ở mức cơ bản như vậy và lãng phí thời gian là rất khó chịu!


Tôi bối rối vì sự phủ định trong tiêu đề. Bạn có muốn grepdòng bắt đầu với hạn. Hay bạn muốn grep cho các dòng không chứa thuật ngữ nào cả?
Bernhard

@Bernhard: Tôi muốn một danh sách không có thuật ngữ trong ngoặc vuông. Nó không phải là "hạn" chính xác! Theo như tôi hiểu, [^ abc] có nghĩa là bất cứ thứ gì có chứa a, b hoặc c hoặc bất kỳ sự kết hợp nào của nó đều không nên có trong danh sách.
erch

Câu trả lời:


12

Bạn có chắc chắn những gì bạn muốn đang xảy ra? Khi bạn chạy, ls /directory | grep '[^term]'về cơ bản bạn đang grepping không phải là chữ ter m. Điều này có nghĩa là nếu một tệp có các chữ cái khác trong tên của nó thì nó vẫn sẽ xuất hiện trong đầu ra của ls. Lấy thư mục sau đây chẳng hạn:

$ ls
alpha  brave  bravo  charlie  delta

Bây giờ nếu tôi chạy, ls |grep '^[brav]'tôi nhận được như sau:

$ ls |grep '^[brav]'
alpha
brave
bravo

Như bạn có thể thấy, tôi không chỉ nhận được bravebravotôi còn nhận được alphabởi vì lớp nhân vật []sẽ nhận được bất kỳ chữ cái nào từ danh sách đó.

Do đó, nếu tôi chạy, ls |grep '[^brav]'tôi sẽ nhận được tất cả các tệp không chứa các ký tự dũng cảm ở bất cứ đâu trong tên.

$ ls |grep '[^brav]'
alpha
bravo
brave
charlie
delta

Nếu bạn nhận thấy nó bao gồm toàn bộ danh sách thư mục vì tất cả các tệp có ít nhất một chữ cái không được bao gồm trong lớp ký tự.

Vì vậy, như Kanvuanza đã nói, để grep cho nghịch đảo của "thuật ngữ" trái ngược với các ký tự t e r mbạn nên làm điều đó bằng cách sử dụng grep -v.

Ví dụ:

$ ls |grep -v 'brav'
alpha
charlie
delta

Ngoài ra nếu bạn không muốn các tệp có bất kỳ ký tự nào trong lớp sử dụng grep -v '[term]'. Điều đó sẽ giữ cho bất kỳ tệp nào hiển thị có bất kỳ ký tự nào trong số đó. (Câu trả lời của Kanvuanza)

Ví dụ:

$ ls |grep -v '[brav]'

Như bạn có thể thấy không có tệp nào được liệt kê vì tất cả các tệp trong thư mục này bao gồm ít nhất một chữ cái từ lớp đó.

Phụ lục:

Tôi muốn thêm rằng sử dụng PCRE, có thể sử dụng chỉ regex để lọc ra bằng cách sử dụng các biểu thức phủ định. Để làm điều này, bạn sẽ sử dụng một cái gì đó được gọi là regex tiêu cực về phía trước : (?!<regex>).

Vì vậy, bằng cách sử dụng ví dụ trên, bạn có thể làm một cái gì đó như thế này để có được kết quả bạn muốn mà không cần sử dụng grepcờ.

$ ls | grep -P '^(?!brav)'
alpha
charlie
delta

Để giải cấu trúc biểu thức chính đó, trước tiên, nó khớp với phần đầu của một dòng ^và sau đó tìm các chuỗi không khớp bravđể theo sau. Chỉ alpha, charliedeltaphù hợp để đó là những người duy nhất được in.


1
Điều này có nghĩa là nếu một tệp có các chữ cái khác trong tên của nó thì nó vẫn sẽ xuất hiện trong đầu ra của ls. Câu trả lời này khá nhiều câu hỏi! :) Vì vậy, cách tốt nhất cho thời điểm này dường như là -vlựa chọn. Cảm ơn sự hỗ trợ của bạn! Câu hỏi này thực sự phá hỏng buổi chiều của tôi, nơi câu trả lời của bạn làm sáng buổi tối của tôi!
erch

+1 cho negative look-ahead regex.
Abhishek Kashyap

3

Tôi đoán rằng grep -vlá cờ làm những gì bạn muốn. Từ trang người đàn ông :

-v, --invert-match
    Invert the sense of matching, to select non-matching lines.

Bạn có thể sử dụng ls /directory | grep -v [term]để in bất kỳ dòng không phù hợp.


Tôi biết về tùy chọn này, nhưng tôi có sai khi cho rằng [^ xyz] trái ngược với [xyz] và nên hoạt động trong mọi trường hợp? Tôi cũng muốn tránh chỉnh sửa bất kỳ cài đặt nào ở bất kỳ đâu ở mức cơ bản như vậy. Sử dụng một tùy chọn đảo ngược và / hoặc cài đặt chỉnh sửa chắc chắn là một cách hay, nhưng theo như tôi hiểu, thì nó sẽ hoạt động mà không cần ra khỏi hộp.
erch

Tôi đoán là bạn đúng, đó là ký hiệu phổ biến cho phủ định lớp (ví dụ. [^abc]Nhưng tôi khá chắc chắn rằng grep không hỗ trợ phủ định lớp, ngoại trừ một vài tiêu chuẩn (ví dụ [[:^digits:]]). Hỗ trợ Grep cho phủ định là khủng khiếp !
Pedro Lacerda

Grep hỗ trợ cho phủ định là khủng khiếp! Và đây là những gợi ý là đóng băng thực sự trên bánh. Tôi có cùng một vấn đề với egrep và tôi không sử dụng [ít nhất là đối với tôi dường như] các lệnh nâng cao hơn vào lúc này. Bạn có thể đề xuất một lệnh cung cấp kết quả tốt hơn và ít đau đầu hơn?
erch

@ cellar.dweller, việc grepxử lý các lớp ký tự là tốt. Nó chỉ có nghĩa là một cái gì đó khá khác với những gì bạn (mis) hiểu. [abc]có nghĩa là một trong những a, bhoặc c; [^abc]có nghĩa là bất cứ điều gì nhưng ở trên. Đây là một nhân vật.
vonbrand

@ cellar.dweller: Tôi nghĩ vấn đề lớn nhất của bạn là sự hiểu lầm về regex, cụ thể là các lớp nhân vật trong regex.
tink
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.