Làm cách nào để loại trừ một số tệp không khớp với các tiện ích mở rộng nhất định với grep?


8

Tôi muốn xuất tất cả các dòng chứa từ OKđệ quy từ một thư mục. Nhưng có một vài phần mở rộng mà tôi cần loại trừ khỏi kết quả:

*~
*.map
*.js except *.debug.js

Tôi đã thử:

grep -r --exclude={*~,*.map} "OK" /some/dir

Ngoại trừ việc tôi không biết cách xóa khỏi kết quả tất cả các .jstệp không gỡ lỗi đó .

Câu trả lời:


7

Tôi sẽ chỉ vượt qua điều đó trong một giây grepđể loại bỏ chúng:

grep -r --exclude={\*~,\*.map} "OK" bar/ | grep -vP '(?<!debug)\.js'

Sự -vđảo ngược khớp, in các dòng không khớp với mẫu và -Pcho phép Biểu thức chính quy tương thích Perl cho phép chúng ta sử dụng các giao diện tiêu cực . Regex cụ thể này, sẽ khớp .jskhông được xác định trước bằng debugphương tiện nào (vì chúng tôi đang đảo ngược các trận đấu) mà chỉ những .jstệp đó sẽ được in.

Tuy nhiên, như @QuestionOverflow đã chỉ ra int các bình luận, điều đó có thể có tác dụng phụ ngoài ý muốn là lọc ra các dòng có chứa OKjsgrep -vnó được áp dụng cho toàn bộ đầu ra, không chỉ tên tệp. Để tránh điều đó, chỉ cần thêm dấu hai chấm (đó là những gì grepsử dụng để tách tên tệp khỏi nội dung tệp):

grep -r --exclude={*~,*.map} "OK" bar/ | grep -vP '(?<!debug).js:'

Điều đó vẫn sẽ thất bại nếu dòng đầu vào của bạn chứa foo.js:hoặc nếu tên tệp của bạn chứa :. Vì vậy, để chắc chắn, sử dụng một cách tiếp cận khác:

grep -Tr --exclude={*~,*.map} "OK" bar/ | grep -vP '(?<!debug).js\t'

Các -Tnguyên nhân grepđể in một tab giữa tên tệp và nội dung tệp. Vì vậy, nếu chúng ta chỉ cần thêm một \tvào cuối regex, nó sẽ chỉ khớp với tên tệp chứ không phải nội dung của dòng.

Tuy nhiên, sử dụngfind có thể có ý nghĩa hơn bất kể.


1
Tôi có vô tình loại trừ các dòng trong các tệp mà tôi muốn, nhưng chứa cả hai OK.jstrên cùng một dòng không?
Câu hỏi tràn

@QuestionOverflow ah, đúng vậy, bắt tốt. Xem câu trả lời cập nhật.
terdon

Câu trả lời tuyệt vời. Phải chấp nhận của bạn kể từ khi tôi yêu cầu cụ thể cho grep. Cảm ơn.
Câu hỏi tràn

@QuestionOverflow bạn rất hoan nghênh. Nói chung, findcó lẽ tốt hơn cho loại điều này. Nhận đúng grepcó thể là khó khăn như bạn chỉ ra :).
terdon

Giải pháp của bạn thất bại nếu ai có failglobbộ tùy chọn trong vỏ: bash: no match: --exclude=*~ Bạn cần phải trích lập luận mẫu GLOB của bạn để --excludeche giấu họ từ việc mở rộng vỏ, ví dụ--exclude={\*~,\*.map}
Ian D. Allen

7

Tôi sẽ sử dụng findđể xác định vị trí các tệp và dẫn kết quả thông qua xargs:

$ find . -type f \! -name "*~" \
                 \! -name "*.map" \
                 \! \( -name "*.js" -and \! -name "*.debug.js" \) \
         -print0 | xargs -0 grep "OK"

Tìm kiếm này cho mọi tệp không khớp " *~", " *.map" hoặc " *.jsnhưng không *.debug.js".

Sử dụng findbạn có thể dễ dàng tìm kiếm các quy tắc khá phức tạp và phương pháp này giúp bạn tránh vô tình loại bỏ các lỗi tích cực có thể xảy ra với gấp đôi grep.


Câu trả lời hay quá :)
Câu hỏi tràn vào

3
Vâng, đây có lẽ là cách tốt nhất, +1. Bạn cũng có thể sử dụng -exec grep OK {} +thay vì xargsvà tránh một chương trình bổ sung.
terdon

2
@ID ALLen không, lưu ý rằng tôi đã đề xuất là -exec +không -exec \;, nó sẽ chạy càng ít lệnh càng tốt, rất giống xargs.
terdon

4

Với zshbạn có thể làm:

setopt extendedglob
grep OK some/dir/**/^(*~|*.map|(^*debug).js)

Tất nhiên với điều kiện là danh sách đối số không quá dài, trong trường hợp đó bạn luôn có thể làm:

printf '%s\0' some/dir/**/^(*~|*.map|(^*debug).js) | xargs -0 grep OK

Ngoài ra, bạn có thể thực hiện lần cuối cùng một lần zsh: autoload zargszargs some/dir/**/^(*~|*.map|(^*debug).js) -- grep OK
don_crissti

2

Nếu bạn không thấy đầu ra hơi sai lệch (nếu có, bạn có thể sắp xếp nó):

grep -r --exclude={*~,*.map,*.js} "OK" /some/dir **/*.debug.js

Điều này đòi hỏi trình bao của bạn hỗ trợ **cho tính năng đệ quy đệ quy: zsh không hoạt động, bash thực hiện sau khi bạn chạy shopt -s globstar, ksh93 thực hiện sau khi bạn chạy set -o globstar.

Không có **hỗ trợ trong shell, bạn có thể sử dụng hai lệnh grep:

grep -r --exclude={*~,*.map,*.js} "OK" /some/dir
grep -r --include=*.debug.js "OK" /some/dir

Shell của tôi hỗ trợ **, nhưng dường như có điều gì đó không đúng với đối số phụ **/*.debug.js, khiến grep hiểu OKnhư là một thư mục. Bạn đã thử chạy nó chưa?
Câu hỏi tràn

@QuestionOverflow Lỗi của tôi, tôi đã hoán đổi thứ tự của các đối số.
Gilles 'SO- ngừng trở nên xấu xa'

2

Bạn có thể sử dụng ripgrep. Theo mặc định, nó bỏ qua các tập tin ẩn và tôn trọng .gitignoretập tin của bạn .

Bạn có thể chỉ định quy tắc bao gồm hoặc loại trừ bằng cách sử dụng các tham số sau:

-g/ --glob GLOBBao gồm hoặc loại trừ các tệp và thư mục để tìm kiếm phù hợp với toàn cầu đã cho.

-t/ --type TYPEChỉ tìm kiếm tệp phù hợp với TYPE. Nhiều loại cờ có thể được cung cấp.

-T/ --type-not TYPEKhông tìm kiếm tệp phù hợp với TYPE.

Sử dụng --type-listcờ để liệt kê tất cả các loại có sẵn.

Dưới đây là một vài ví dụ đơn giản:

rg -Tjs "OK"                              # Excludes *.js, *.jsx, *.vue files.
rg -tpy "OK"                              # Includes Python files.
rg --type-add 'map:*.map' -tmap PATTERN   # Excludes *.map files.
rg -g '!*.js' -g '*.debug.js' PATTERN     # Excludes *.js apart of *.debug.js.

Đây là giải pháp hoàn chỉnh để loại trừ *.~, *.map, *.js, nhưng không phải *.debug.js:

rg -g '*.*' -g '!*.~' -g '!*.map' -g '!*.js' -g '*.debug.js' "OK"

Kiểm tra:

$ touch file.~ file.map file.js file.debug.js file.txt file.md
$ rg --files
file.debug.js
file.js
file.map
file.md
file.txt
$ rg -g '*.*' -g '!*.~' -g '!*.map' -g '!*.js' -g '*.debug.js' --files
file.debug.js
file.md
file.txt
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.