Làm cách nào để tìm các tệp không chứa mẫu chuỗi đã cho?


536

Làm cách nào để tìm ra các tệp trong thư mục hiện tại không chứa từ foo(đang sử dụng grep)?

Câu trả lời:


818

Nếu grep của bạn có tùy chọn -L(hoặc --files-without-match):

$ grep -L "foo" *

1
Như đã chỉ ra ở nơi khác, ack giúp tránh các tệp .svn (lật đổ) theo mặc định.
Giáo sư

11
@GuruM Điều này có thể được thực hiện trong GNU grep bằng cách xuất biến GREP_OPTIONS='--exclude-dir=.svn --exclude-dir=.git': ^)
bufh

6
Hoặc tương đương bằng cách sử dụng ag :ag -L 'foo'
giám mục

5
Hoạt động như ma thuật! Gợi ý: sử dụng -rLthay vì -Lkhớp với các thư mục con
Ufos

1
@Larry - Một cách sạch hơn để tránh các vấn đề toàn cầu là sử dụng tùy chọn dài "trống" như thế này: grep -L 'foo' -- *Tiêu chuẩn là các lệnh có các tùy chọn dài sử dụng --để chỉ ra rằng không có thêm tùy chọn nào sau thời điểm này.
Paddy Landau

45

Hãy nhìn vào ack. Nó .svntự động loại trừ cho bạn, cung cấp cho bạn các biểu thức chính quy Perl và là một bản tải xuống đơn giản của một chương trình Perl.

Tương đương với những gì bạn đang tìm kiếm nên có, trong ack:

ack -L foo

24

Bạn có thể làm điều đó với grep một mình (mà không tìm thấy).

grep -riL "foo" .

Đây là giải thích về các tham số được sử dụng trên grep

     -L, --files-without-match
             each file processed.
     -R, -r, --recursive
             Recursively search subdirectories listed.

     -i, --ignore-case
             Perform case insensitive matching.

Nếu bạn sử dụng l(hạ cấp), bạn sẽ nhận được điều ngược lại (các tệp có kết quả khớp)

     -l, --files-with-matches
             Only the names of files containing selected lines are written

17

Lệnh sau cung cấp cho tôi tất cả các tệp không chứa mẫu foo:

find .  -not  -ipath '.*svn*' -exec  grep  -H -E -o -c  "foo"  {} \; | grep 0

4
Bạn muốn thay đổi grep 0 ở cuối thành grep 0 $ (nếu không, bạn sẽ nhận được các kết quả khớp sai trên các tệp có ký tự 0 trong tên tệp của chúng).
clouseau

9
@clouseau hầu như đúng ... Tuy nhiên, grep '0$'cũng sẽ khớp các tệp với bội số của 10 dòng! Bạn cần grep ':0$'ở cuối để kiểm tra rõ ràng ': 0' ở cuối dòng. Sau đó, bạn sẽ chỉ nhận được các tập tin có dòng không khớp.
TrinitronX

UNIX Tôi không có các phiên bản tìm hoặc grep với các tùy chọn này, vì vậy tôi đã phải sử dụng lệnh "ack" được đề xuất trong các nhận xét khác.
KC Baltz

14

Lệnh sau không bao gồm nhu cầu tìm kiếm để lọc các svnthư mục bằng cách sử dụng giây grep.

grep -rL "foo" ./* | grep -v "\.svn"

9

Bạn thực sự sẽ cần:

find .  -not  -ipath '.*svn*' -exec  grep  -H -E -o -c  "foo"  {} \; | grep :0\$

6

Tôi đã có may mắn với

grep -H -E -o -c "foo" */*/*.ext | grep ext:0

Những nỗ lực của tôi grep -vchỉ cho tôi tất cả các dòng mà không có "foo".


4

Vấn đề

Tôi cần cấu trúc lại một dự án lớn sử dụng .phtmlcác tệp để viết HTML bằng mã PHP nội tuyến. Tôi muốn sử dụng các mẫu Mustache thay thế. Tôi muốn tìm bất kỳ .phtmlgiles nào không chứa chuỗi new Mustachevì chúng vẫn cần phải viết lại.

Giải pháp

find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$ | sed 's/..$//'

Giải trình

Trước các đường ống:

Tìm thấy

find . Tìm tệp đệ quy, bắt đầu trong thư mục này

-iname '*.phtml'Tên tệp phải chứa .phtml( ilàm cho nó không phân biệt chữ hoa chữ thường)

-exec 'grep -H -E -o -c 'new Mustache' {}'Chạy greplệnh trên mỗi đường dẫn phù hợp

Grep

-H Luôn in các tiêu đề tên tệp với các dòng đầu ra.

-E Mẫu diễn giải như một biểu thức chính quy mở rộng (tức là buộc grep hành xử như egrep).

-o Chỉ in phần phù hợp của các dòng.

-c Chỉ có một số dòng được chọn được ghi vào đầu ra tiêu chuẩn.


Điều này sẽ cho tôi một danh sách tất cả các đường dẫn tệp kết thúc .phtmlbằng số đếm số lần chuỗi new Mustachexảy ra trong mỗi đường dẫn.

$> find . -iname '*.phtml$' -exec 'grep -H -E -o -c 'new Mustache' {}'\;

./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0
./app/MyApp/Customer/View/Account/studio.phtml:0
./app/MyApp/Customer/View/Account/orders.phtml:1
./app/MyApp/Customer/View/Account/banking.phtml:1
./app/MyApp/Customer/View/Account/applycomplete.phtml:1
./app/MyApp/Customer/View/Account/catalogue.phtml:1
./app/MyApp/Customer/View/Account/classadd.phtml:0
./app/MyApp/Customer/View/Account/orders-trade.phtml:0

Ống đầu tiên grep :0$lọc danh sách này chỉ bao gồm các dòng kết thúc bằng :0:

$> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$

./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0
./app/MyApp/Customer/View/Account/studio.phtml:0
./app/MyApp/Customer/View/Account/classadd.phtml:0
./app/MyApp/Customer/View/Account/orders-trade.phtml:0

Ống thứ hai sed 's/..$//'loại bỏ hai ký tự cuối cùng của mỗi dòng, chỉ để lại các đường dẫn tệp.

$> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$ | sed 's/..$//'

./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml
./app/MyApp/Customer/View/Account/studio.phtml
./app/MyApp/Customer/View/Account/classadd.phtml
./app/MyApp/Customer/View/Account/orders-trade.phtml

3

Nếu bạn đang sử dụng git, điều này sẽ tìm kiếm tất cả các tệp được theo dõi:

git grep -L "foo"

và bạn có thể tìm kiếm trong một tập hợp con các tệp được theo dõi nếu bạn đã bật ** thư mục con thư mục con ( shopt -s globstartrong .bashrc, xem phần này ):

git grep -L "foo" -- **/*.cpp

1

Grep của tôi không có tùy chọn -L. Tôi tìm cách giải quyết để đạt được điều này.

Các ý tưởng là:

  1. để kết xuất tất cả tên tệp chứa chuỗi xứng đáng vào txt1.txt.
  2. kết xuất tất cả tên tệp trong thư mục vào txt2.txt.
  3. tạo sự khác biệt giữa 2 tệp kết xuất với lệnh diff.

    grep 'foo' *.log | cut -c1-14 | uniq > txt1.txt
    grep * *.log | cut -c1-14 | uniq > txt2.txt
    diff txt1.txt txt2.txt | grep ">"
    

Tôi quên các lệnh nhưng thay vì bỏ tên tệp, bạn thực sự có thể thực hiện diffgiữa hai luồng đầu ra (tôi nghĩ rằng bạn bao quanh các lệnh bằng dấu ngoặc đơn và cũng có một khung góc ở đó ở đâu đó), nếu hệ thống của bạn hỗ trợ nó, tôi đoán vậy là câu hỏi, vì nó không hỗ trợgrep -L
Dexygen

1

find *20161109* -mtime -2|grep -vwE "(TRIGGER)"

Bạn có thể chỉ định bộ lọc trong "tìm" và chuỗi loại trừ trong "grep -vwE". Sử dụng mtime dưới find nếu bạn cũng cần lọc theo thời gian đã sửa đổi.


Điều này dường như hiển thị cho tôi tất cả các dòng mà không có chuỗi, OP chỉ yêu cầu tên tệp.
Nông dân Ben

1

Báo cáo lỗi mở

Theo nhận xét của @tukan, có một báo cáo lỗi mở cho Ag liên quan đến -L/ --files-without-matchescờ:

Vì có ít tiến triển trong báo cáo lỗi, không nên dựa vào-L tùy chọn được đề cập dưới đây , miễn là lỗi chưa được giải quyết. Sử dụng các phương pháp khác nhau được trình bày trong chủ đề này thay thế. Trích dẫn một bình luận cho báo cáo lỗi [nhấn mạnh của tôi]:

Bất kỳ cập nhật về điều này? -Lhoàn toàn bỏ qua các trận đấu trên dòng đầu tiên của tập tin. Có vẻ như nếu điều này sẽ không được khắc phục sớm, cờ sẽ bị xóa hoàn toàn, vì nó thực sự không hoạt động như quảng cáo .


Trình tìm kiếm bạc - Ag (chức năng dự định - xem báo cáo lỗi)

Để thay thế mạnh mẽ grep, bạn có thể sử dụng Trình tìm kiếm bạc - Ag :

Một công cụ tìm kiếm mã tương tự như ack, tập trung vào tốc độ.

Nhìn vào man ag, chúng tôi tìm thấy -Lhoặc --files-without-matchestùy chọn:

...

OPTIONS
    ...

    -L --files-without-matches
           Only print the names of files that don´t contain matches.

Tức là, để tìm kiếm đệ quy các tệp không khớp foo, từ thư mục hiện tại:

ag -L foo

Để chỉ tìm kiếm thư mục hiện tại cho các tệp không khớp foo, chỉ cần chỉ định --depth=0cho đệ quy:

ag -L foo --depth 0

Điều này thất bại theo thời gian do -Llỗi - github.com/ggreer/the_silver_searcher/issues/238
tukan

@tukan cảm ơn đã nhắc nhở. Tôi đã cập nhật câu trả lời; chọn không xóa câu trả lời mà thay vào đó mở bằng thông tin liên quan đến lỗi.
dfri

1

một lựa chọn khác khi grep không có tùy chọn -L (ví dụ IBM AIX), không có gì ngoài grep và shell:

for file in * ; do grep -q 'my_pattern' $file || echo $file ; done

-4
grep -irnw "filepath" -ve "pattern"

hoặc là

grep -ve "pattern" < file

Lệnh trên sẽ cho chúng ta kết quả khi -v tìm thấy nghịch đảo của mẫu đang được tìm kiếm


1
Điều này in các dòng không chứa mẫu. Bạn có thể thêm -ltùy chọn để chỉ in tên tệp; nhưng điều này vẫn in tên của bất kỳ tệp nào chứa bất kỳ dòng nào không chứa mẫu. Tôi tin rằng OP muốn tìm các tệp không chứa bất kỳ dòng nào chứa mẫu.
tripleee

Lệnh bạn đã cung cấp danh sách các tệp trong "filepath" với tất cả các dòng không chứa "mẫu".
aprodan

-6

Lệnh sau có thể giúp bạn lọc các dòng bao gồm chuỗi con "foo".

cat file | grep -v "foo"

2
Điều này in các dòng không khớp, không phải tên của các tệp không chứa khớp trên bất kỳ dòng nào. Để thêm sự xúc phạm đến thương tích, nó như là một cách sử dụng vô dụngcat .
tripleee
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.