Làm thế nào để tôi grep đệ quy?


1682

Làm thế nào để tôi đệ quy greptất cả các thư mục và thư mục con?

find . | xargs grep "texthere" *

110
@ TC1 Điều đáng buồn là chính grep có thể trả lời câu hỏi (ít nhất là GNU grep): grep --help | grep đệ quy
Frank Schmitt

7
Nếu bạn thấy mình thường xuyên sử dụng grep để thực hiện các tìm kiếm đệ quy (đặc biệt là nếu bạn thực hiện thủ công nhiều tệp / thư mục), bạn có thể thấy ack (một thay thế grep rất thân thiện với lập trình viên) hữu ích.
Nick McCurdy

19
Trên thực tế, không phải công việc -r hay - recursive trên hộp Solaris mà tôi sử dụng tại nơi làm việc. Và trang man cho grep không đề cập đến bất cứ điều gì đệ quy. Tôi đã phải dùng đến để tìm và xargs mình.
Ben

8
ag là cách yêu thích của tôi để làm điều này ngay bây giờ github.com/ggreer/the_silver_searcher
dranxo

1
grep -rin xlsx *.plkhông hoạt động với tôi trên Redhat Linux. Tôi nhận được một lỗi "không khớp".
Bulrush

Câu trả lời:


2507
grep -r "texthere" .

Tham số đầu tiên biểu thị biểu thức chính quy cần tìm kiếm, trong khi tham số thứ hai biểu thị thư mục cần tìm kiếm. Trong trường hợp này, .có nghĩa là thư mục hiện tại.

Lưu ý: Điều này hoạt động với GNU grep và trên một số nền tảng như Solaris, bạn phải đặc biệt sử dụng GNU grep thay vì triển khai kế thừa. Đối với Solaris đây là ggreplệnh.


39
Lưu ý: "grep -r" chỉ hoạt động trên các greps mới hơn. Nó không hoạt động trên grep đi kèm AIX 5.3chẳng hạn.
Giữ lại

110
Sử dụng grep -R để theo liên kết tượng trưng.
Eloff

53
Thật tốt khi biết rằng "-i" sẽ làm cho trường hợp không nhạy cảm và "-n" cũng bao gồm số dòng cho mỗi kết quả phù hợp.
Sadegh

24
cũng nên biết, nếu bạn chỉ tìm kiếm một chuỗi cố định chứ không phải regex, hãy sử dụng tùy chọn -F. nó sẽ giúp bạn tiết kiệm thời gian bằng cách không gọi trình phân tích cú pháp regex. rất tiện dụng nếu bạn đang tìm kiếm nhiều tập tin
Jeff

6
bí danh rgrep = 'grep -r'
lấy

679

Nếu bạn biết phần mở rộng hoặc mẫu của tệp bạn muốn, một phương pháp khác là sử dụng --includetùy chọn:

grep -r --include "*.txt" texthere .

Bạn cũng có thể đề cập đến các tập tin để loại trừ với --exclude.

Ag

Nếu bạn thường xuyên tìm kiếm thông qua mã, Ag (Trình tìm kiếm bạc) là một thay thế nhanh hơn nhiều so với grep, đó là tùy chỉnh để tìm kiếm mã. Chẳng hạn, nó được đệ quy theo mặc định và tự động bỏ qua các tệp và thư mục được liệt kê trong đó .gitignore, vì vậy bạn không phải tiếp tục chuyển các tùy chọn loại trừ rườm rà tương tự để grep hoặc find.


3
Hoạt động tuyệt vời với grep đi kèm với Linux & Cygwin, nhưng không hoạt động với AIX đi kèm với AIX.
Giữ lại

1
@KrzysztofWolny: `` thay vì =hoạt động tốt trên Ubuntu. PS: đó được coi là một không gian được sao lưu, nhưng trình phân tích cú pháp đánh dấu SO đã thất bại.
Dan Dascalescu

4
@DanDascalescu Tôi ủng hộ cho grep, không phải cho Ag, chỉ để bạn biết :)
Bernhard

1
Chúng ta có một tùy chọn để loại trừ một thư mục trong khi tìm kiếm đệ quy không?
Tom Taylor

Windows Cygwin thích trích dẫn kép--include "*.txt" --include "*.TXT"
Bob Stein

127

Cũng thế:

find ./ -type f -print0 | xargs -0 grep "foo"

nhưng grep -rlà một câu trả lời tốt hơn


14
Hoặc nếu bạn không muốn lo lắng về không gian trong tên tệp find . -type f -exec grep "foo" '{}' \;hoạt động tốt ở những nơi được hỗ trợ.
Edd Steel

4
Nếu bạn định tìm đường ống qua xargs đến grep, VÀ nếu bạn chỉ tìm kiếm một chuỗi cố định (nghĩa là không phải regex), bạn có thể hưởng lợi từ việc gọi tùy chọn grep -F, vì vậy grep sẽ không tải công cụ regex cho mỗi lần gọi Nếu có nhiều tập tin thì nó sẽ nhanh hơn nhiều.
Jeff

2
tìm thấy . -type f -exec grep -Hu "foo" {} \; là những gì tôi sử dụng vì nó cung cấp tên tệp.
Wes

Điều này hoạt động trên tất cả * nix vì đó là POSIX 7
Ciro Santilli 冠状 病毒 审查 六四 法轮功

1
find ./ -type f -print0 | xargs -0 grep "foo"
aehlke

118

Bây giờ tôi luôn sử dụng (ngay cả trên Windows với GoW - Gnu trên Windows ):

grep --include="*.xxx" -nRHI "my Text to grep" *

Điều đó bao gồm các tùy chọn sau:

--include=PATTERN

Recurse trong thư mục chỉ tìm kiếm tập tin phù hợp PATTERN.

-n, --line-number

Tiền tố mỗi dòng đầu ra với số dòng trong tệp đầu vào của nó.

(Lưu ý: phuclv thêm trong các ý kiến đó -nlàm giảm hiệu suất rất nhiều vì vậy , vì vậy bạn có thể muốn bỏ qua tùy chọn đó)

-R, -r, --recursive

Đọc tất cả các tệp trong mỗi thư mục, đệ quy; Điều này tương đương với -d recursetùy chọn.

-H, --with-filename

In tên tệp cho mỗi trận đấu.

-I     

Xử lý một tệp nhị phân như thể nó không chứa dữ liệu phù hợp;
Điều này tương đương với --binary-files=without-matchtùy chọn.

Và tôi có thể thêm ' i' ( -nRHIi), nếu tôi muốn kết quả không phân biệt chữ hoa chữ thường.

Tôi co thể lây:

/home/vonc/gitpoc/passenger/gitlist/github #grep --include="*.php" -nRHI "hidden" *
src/GitList/Application.php:43:            'git.hidden'      => $config->get('git', 'hidden') ? $config->get('git', 'hidden') : array(),
src/GitList/Provider/GitServiceProvider.php:21:            $options['hidden'] = $app['git.hidden'];
tests/InterfaceTest.php:32:        $options['hidden'] = array(self::$tmpdir . '/hiddenrepo');
vendor/klaussilveira/gitter/lib/Gitter/Client.php:20:    protected $hidden;
vendor/klaussilveira/gitter/lib/Gitter/Client.php:170:     * Get hidden repository list
vendor/klaussilveira/gitter/lib/Gitter/Client.php:176:        return $this->hidden;
...

Gow có vẻ đầy hứa hẹn - mới hơn các tiện ích GNU Windows mà tôi đang sử dụng.
Dùng

ý nghĩa của ký tự cuối cùng * ở đây là gì?
lorniper

2
@lorniper nó làm cho shell chọn tất cả các tệp và thư mục trong thư mục hiện tại của bạn, lần lượt grep áp dụng cho các tệp đó và (đệ quy vì -Rtùy chọn) cho các thư mục.
VonC

2
@lorniper Noy chính xác: *hoặc .là một mô hình toàn cầu (được giải thích bởi trình bao): unix.stackexchange.com/a/64695/7490 . ' .' cũng sẽ chọn các thư mục dotfiles hoặc dot (như .git/)
VonC

trước đây tôi đã luôn sử dụng grep -rnInhưng sau đó tôi đã học được rằng -nlàm giảm hiệu suất rất nhiều vì vậy tôi chỉ sử dụng nó khi thực sự cần thiết và thông thường tôi sẽ sử dụng-rI
phuclv

25

Trong các hệ thống POSIX, bạn không tìm thấy -rtham số cho grepvà bạn grep -rn "stuff" .sẽ không chạy, nhưng nếu bạn sử dụng findlệnh thì nó sẽ:

find . -type f -exec grep -n "stuff" {} \; -print

Đồng ý bởi SolarisHP-UX.


ý nghĩa của {} \; -print tương ứng?
dùng1169587

3
Trong -exectùy chọn - biểu tượng {}là một tham chiếu đến tên tệp hiện được tìm thấy bởi findcông cụ (nghĩa là làm một cái gì đó với tên tệp mà chúng ta đã tìm thấy), cũng -execnên kết thúc tùy chọn bằng ;ký hiệu (để đánh dấu kết thúc của lệnh exec), nhưng vì đây là tất cả chạy trong một vỏ mà biểu tượng nên được thoát .. và cuối cùng -printtùy chọn cho phép findcông cụ in ra tên tệp tìm thấy trên màn hình.
rook

19

hình cầu **

Sử dụng grep -rcông việc, nhưng nó có thể quá mức, đặc biệt là trong các thư mục lớn.

Để sử dụng thực tế hơn, đây là cú pháp sử dụng cú pháp toàn cầu ( **):

grep "texthere" **/*.txt

mà chỉ greps các tập tin cụ thể với mẫu đã chọn mẫu. Nó hoạt động cho các shell được hỗ trợ như Bash +4 hoặc zsh .

Để kích hoạt tính năng này, hãy chạy : shopt -s globstar.

Xem thêm: Làm cách nào để tìm tất cả các tệp chứa văn bản cụ thể trên Linux?

git grep

Đối với các dự án dưới sự kiểm soát phiên bản Git, hãy sử dụng:

git grep "pattern"

đó là nhanh hơn nhiều.

ripgrep

Đối với các dự án lớn hơn, công cụ grepping nhanh nhất là ripgrepcác tệp greps theo cách đệ quy theo mặc định:

rg "pattern" .

Nó được xây dựng trên đỉnh công cụ regex của Rust , sử dụng automata hữu hạn, SIMD và tối ưu hóa theo nghĩa đen tích cực để giúp tìm kiếm rất nhanh. Kiểm tra phân tích chi tiết tại đây .


3
Cảm ơn lời đề nghị git grep - nó rất hữu ích và tôi không biết về nó!
Basya

2
Cảm ơn lời đề nghị ripgrep. Đó là cách nhanh hơn.
Điều gì sẽ tuyệt vời vào

11

Để tìm tên filesvới pathđệ quy có chứa các đặc biệt stringsử dụng dưới lệnh cho UNIX:

find . | xargs grep "searched-string"

cho Linux:

grep -r "searched-string" .

tìm một tập tin trên UNIXmáy chủ

find . -type f -name file_name

tìm một tập tin trên máy chủ LINUX

find . -name file_name

11

tên tập tin cũng có thể hữu ích

grep -r -l "foo" .

10

Nếu bạn chỉ muốn theo dõi các thư mục thực tế, và không liên kết tượng trưng,

grep -r "thingToBeFound" directory

Nếu bạn muốn theo các liên kết tượng trưng cũng như các thư mục thực tế (hãy cẩn thận với đệ quy vô hạn),

grep -R "thing to be found" directory

Vì bạn đang cố gắng grep đệ quy, các tùy chọn sau cũng có thể hữu ích cho bạn:

-H: outputs the filename with the line

-n: outputs the line number in the file

Vì vậy, nếu bạn muốn tìm tất cả các tệp chứa Darth Vader trong thư mục hiện tại hoặc bất kỳ thư mục con nào và chụp tên tệp và số dòng, nhưng không muốn đệ quy theo các liên kết tượng trưng, ​​lệnh sẽ là

grep -rnH "Darth Vader" .

Nếu bạn muốn tìm tất cả các đề cập đến từ mèo trong thư mục

/home/adam/Desktop/TomAndJerry 

và bạn hiện đang ở trong thư mục

/home/adam/Desktop/WorldDominationPlot

và bạn muốn chụp tên tệp nhưng không phải là số dòng của bất kỳ trường hợp nào của chuỗi "mèo" và bạn muốn đệ quy theo các liên kết tượng trưng nếu tìm thấy chúng, bạn có thể chạy một trong các cách sau

grep -RH "cats" ../TomAndJerry                   #relative directory

grep -RH "cats" /home/adam/Desktop/TomAndJerry   #absolute directory

Nguồn:

chạy "grep - trợ giúp"

Giới thiệu ngắn về các liên kết tượng trưng, ​​cho bất kỳ ai đọc câu trả lời này và bối rối bởi tài liệu tham khảo của tôi cho họ: https://www.nixtutor.com/freebsd/under Hiểu-symbolic-links /


Câu trả lời chính xác. Các công tắc phụ (-rnh) rất hữu ích, vì vậy cảm ơn bạn đã gợi ý chúng.
semtex41

8

ag là cách yêu thích của tôi để làm điều này ngay bây giờ github.com/ggreer/the_silver_searcher . Về cơ bản nó giống như ack nhưng với một vài tối ưu hóa hơn.

Đây là một điểm chuẩn ngắn. Tôi xóa bộ nhớ cache trước mỗi bài kiểm tra (cf https://askubfox.com/questions/155768/how-do-i-clean-or-disable-the-memory-cache )

ryan@3G08$ sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
3
ryan@3G08$ time grep -r "hey ya" .

real    0m9.458s
user    0m0.368s
sys 0m3.788s
ryan@3G08:$ sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
3
ryan@3G08$ time ack-grep "hey ya" .

real    0m6.296s
user    0m0.716s
sys 0m1.056s
ryan@3G08$ sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
3
ryan@3G08$ time ag "hey ya" .

real    0m5.641s
user    0m0.356s
sys 0m3.444s
ryan@3G08$ time ag "hey ya" . #test without first clearing cache

real    0m0.154s
user    0m0.224s
sys 0m0.172s


6

Nếu bạn đang tìm kiếm một nội dung cụ thể trong tất cả các tệp từ cấu trúc thư mục, bạn có thể sử dụng findvì nó rõ ràng hơn những gì bạn đang làm:

find -type f -exec grep -l "texthere" {} +

Lưu ý rằng -l(chữ thường của L) hiển thị tên của tệp chứa văn bản. Hủy bỏ nó nếu bạn muốn in trận đấu chính nó. Hoặc sử dụng -Hđể có được các tập tin cùng với trận đấu. Tất cả cùng nhau, các lựa chọn thay thế khác là:

find -type f -exec grep -Hn "texthere" {} +

Trường hợp -nin số dòng.


2
Up-bình chọn cho là chỉ findgiải pháp cho cả hai tránh sử dụng không cần thiết của xargsvà sử dụng +thay vì \;với -exec, do đó tránh được tấn của quá trình ra mắt không cần thiết. :-)
ShadowRanger

6

Đây là cái đã hoạt động cho trường hợp của tôi trên máy hiện tại của tôi (git bash trên windows 7):

find ./ -type f -iname "*.cs" -print0 | xargs -0 grep "content pattern"

Tôi luôn quên -print0 và -0 cho các đường dẫn có khoảng trắng.

EDIT: Công cụ ưa thích của tôi bây giờ thay vì ripgrep: https://github.com/BurntSushi/ripgrep/release . Nó thực sự nhanh và có mặc định tốt hơn (như đệ quy theo mặc định). Ví dụ giống như câu trả lời ban đầu của tôi nhưng sử dụng ripgrep:rg -g "*.cs" "content pattern"


4

grep -r "texthere" . (thời gian thông báo ở cuối)

(^ tín dụng: https://stackoverflow.com/a/1987928/1438029 )


Làm rõ:

grep -r "texthere" / (grep đệ quy tất cả các thư mục và thư mục con)

grep -r "texthere" .(đệ quy grep các thư mục và thư mục con này)

đệ quy grep

grep [options] PATTERN [FILE...]

[tùy chọn]

-R, -r, --recursive

Đọc tất cả các tập tin dưới mỗi thư mục, đệ quy.

Điều này tương đương với -d recursehoặc--directories=recurse tùy chọn.

http://linuxcommand.org/man_pages/grep1.html

giúp đỡ

$ grep --help

$ grep --help |grep recursive
  -r, --recursive           like --directories=recurse
  -R, --dereference-recursive

Lựa chọn thay thế

ack( http://beyondgrep.com/ )

ag( http://github.com/ggreer/the_silver_searcher )


4

Năm 2018, bạn muốn sử dụng ripgrephoặc the-silver-searchervì chúng nhanh hơn các lựa chọn thay thế.

Đây là một thư mục với 336 thư mục con cấp đầu tiên:

% find . -maxdepth 1 -type d | wc -l
     336

% time rg -w aggs -g '*.py'
...
rg -w aggs -g '*.py'  1.24s user 2.23s system 283% cpu 1.222 total

% time ag -w aggs -G '.*py$'
...
ag -w aggs -G '.*py$'  2.71s user 1.55s system 116% cpu 3.651 total

% time find ./ -type f -name '*.py' | xargs grep -w aggs
...
find ./ -type f -name '*.py'  1.34s user 5.68s system 32% cpu 21.329 total
xargs grep -w aggs  6.65s user 0.49s system 32% cpu 22.164 total

Trên OSX, cài đặt này ripgrep: brew install ripgrep. Cài đặt này silver-searcher: brew install the_silver_searcher.


Tốc độ là quan trọng nếu bạn cần làm điều này thường xuyên, nhưng hầu hết chúng ta thấy mình chỉ làm điều này một vài lần một năm. Cài đặt công cụ juju của bên thứ ba mới nhất là quá mức cần thiết và các giải pháp không thay đổi nhiều kể từ năm 1978 là điều tốt để biết bất kể.
tripleee

Tôi thấy rất hợp lý khi một lập trình viên sẽ tìm kiếm văn bản trong cây nguồn chỉ vài lần mỗi năm. Nhưng ngay cả từ quan điểm về khả năng sử dụng, rgcó một lợi thế đáng kể so với việc gắn kết một lệnh grep đệ quy từ đầu. Sử dụng rg: rg foo. Sử dụng các công cụ unix : find . | xargs grep foo. Và nếu bất kỳ tệp nào của bạn có trích dẫn trong đó, bạn cần sử dụng find . -print0 | xargs -0 grep foo. Bạn sẽ nhớ rằng nếu bạn sử dụng điều này một vài lần một năm?
hughdbrown

1
Bạn đang quên find . -type f -exec grep 'regex' {} +điều thực sự dễ nhớ nếu bạn sử dụng những công cụ này với bất kỳ sự thường xuyên nào. Nhưng có lẽ bạn vẫn nên chạy ctagshoặc etagstrên cây nguồn của mình nếu bạn cần tìm công cụ thường xuyên.
tripleee

Tôi đã sử dụng ripgrep và nó rất tuyệt. Nhưng tìm kiếm bạc là tuyệt vời cho các lập trình viên. +1
Matt

3

Trong Máy chủ IBM AIX của tôi (phiên bản HĐH: AIX 5.2), sử dụng:

find ./ -type f -print -exec grep -n -i "stringYouWannaFind" {} \; 

điều này sẽ in ra đường dẫn / tên tệp và số dòng tương đối trong tệp như:

./inc/xxxx_x.h

2865: / ** Mô tả: chuỗiYouWannaFind * /

dù sao, nó hoạt động với tôi :)


3

Dưới đây là lệnh để tìm kiếm Stringđệ quy trên UnixLinux môi trường.

cho UNIXlệnh là:

find . -name "string to be searched" -exec grep "text" "{}" \;

cho Linuxlệnh là:

grep -r "string to be searched" .

2

Đối với một danh sách các cờ có sẵn:

grep --help 

Trả về tất cả các kết quả khớp cho văn bản regrec trong thư mục hiện tại, với số dòng tương ứng:

grep -rn "texthere" .

Trả về tất cả các kết quả khớp cho texthere , bắt đầu từ thư mục gốc, với số dòng tương ứng và trường hợp bỏ qua:

grep -rni "texthere" /

cờ được sử dụng ở đây:

  • -r đệ quy
  • -n in số dòng với đầu ra
  • -i bỏ qua trường hợp

1

Tôi đoán đây là những gì bạn đang cố viết

grep myText $(find .)

và điều này có thể là một cái gì đó hữu ích nếu bạn muốn tìm các tập tin grep hit

grep myText $(find .) | cut -d : -f 1 | sort | uniq

Nó rất trực quan: ví dụ: grep -i acc $ (tìm. -Tên "thực thi *. *")
Yu Shen

1

Ném hai xu của tôi vào đây. Như những người khác đã đề cập grep -r không hoạt động trên mọi nền tảng. Điều này nghe có vẻ ngớ ngẩn nhưng tôi luôn sử dụng git.

git grep "texthere"

Ngay cả khi thư mục không được dàn dựng, tôi chỉ giai đoạn nó và sử dụng git grep.


0

Lưu ý rằng find . -type f | xargs grep whatever các loại giải pháp sẽ chạy vào lỗi "Danh sách đối số dài" khi có quá nhiều tệp phù hợp với tìm kiếm.

Đặt cược tốt nhất là grep -rnhưng nếu điều đó không có sẵn, find . -type f -exec grep -H whatever {} \;thay vào đó hãy sử dụng .


Huh? xargsđặc biệt là một cách giải quyết cho vấn đề "Danh sách đối số quá dài".
tripleee

2
Chà, không - xargs đặc biệt để chuyển đổi một ống các đối số thành một đối số, nhưng đúng, đúng là các xargs hiện đại khi được sử dụng với -s và / hoặc -L có thể xử lý các trình duyệt rất dài bằng cách đột nhập vào nhiều lệnh khác nhau, nhưng nó không được cấu hình theo cách đó theo mặc định (và không có trong bất kỳ phản hồi nào ở trên). Ví dụ:find . -type f | xargs -L 100 grep whatever
m.thome

Nền tảng nào sẽ được trên? POSIXxargs được chuẩn hóa để loại bỏ hành vi này. " xargsTiện ích sẽ giới hạn độ dài dòng lệnh sao cho khi dòng lệnh được gọi, đối số kết hợp và danh sách môi trường ... sẽ không vượt quá {ARG_MAX} -2048 byte."
tripleee

Hừm. Mặc dù các tài liệu gnu không rõ ràng hơn so với posix trên cơ sở này và tôi không còn có quyền truy cập vào máy khiến tôi đưa ra tuyên bố này, tôi không thể xác nhận giải thích ban đầu của mình về bất kỳ triển khai hiện tại nào. Grep đệ quy, tất nhiên, vẫn thích hợp hơn nếu có, nhưng có rất ít lý do để tránh công thức xargs (sử dụng -H cho grep để tránh lệnh grep cuối cùng chỉ được truyền một tên tệp duy nhất).
m.thome

0

Để giải trí, một tìm kiếm nhanh và bẩn các tệp * .txt nếu câu trả lời @christangrant quá nhiều để nhập :-)

grep -r texthere .|grep .txt


0

Đây là một hàm đệ quy (được kiểm tra nhẹ với hàm bash và sh) đi qua tất cả các thư mục con của một thư mục đã cho ($ 1) và sử dụng grepcác tìm kiếm cho chuỗi đã cho ($ 3) trong các tệp đã cho ($ 2):

$ cat script.sh
#!/bin/sh

cd "$1"

loop () {
    for i in *
    do
        if [ -d "$i" ]
        then
            # echo entering "$i"
            cd "$i"
            loop "$1" "$2"
        fi
    done

    if [ -f "$1" ]
    then
        grep -l "$2" "$PWD/$1"
    fi

    cd ..
}

loop "$2" "$3"

Chạy nó và một ví dụ đầu ra:

$ sh script start_folder filename search_string
/home/james/start_folder/dir2/filename

-2
The syntax is:
cd /path/to/dir
grep -r <"serch_word name"> .

7
Điều này không thêm nhiều vào các câu trả lời khác
Mel
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.