Làm thế nào để sử dụng grep trên tất cả các tệp không đệ quy trong một thư mục?


34

Tôi muốn tìm kiếm một chuỗi văn bản trong tất cả các tệp trong một thư mục (và không phải thư mục con của nó; tôi biết -rtùy chọn thực hiện điều đó, nhưng đó không phải là điều tôi muốn).

  1. Đang chạy

    grep "string" /path/to/dir
    

    được cho là có thể làm điều này, tôi đã đọc, nhưng nó cho tôi lỗi:

    grep: dir: Là một thư mục

  2. Tiếp theo, tôi đã thử chạy grep trên nhiều tập tin.

    grep "string" .bashrc .bash_aliases hoạt động hoàn hảo.

    grep "string" .bash* hoạt động như dự định quá.

    grep "string" * cho tôi các lỗi:

    grep: data: Is a directory
    grep: Desktop: Is a directory
    grep: Documents: Is a directory
    grep: Downloads: Is a directory
    ...
    

Chỉ các lỗi được in, tôi không nhận được các dòng phù hợp. Tôi đã thử sử dụng-s tùy chọn, nhưng không có kết quả.

Vì vậy, câu hỏi của tôi:

  1. Tại sao tôi không thể sử dụng greptrên một thư mục, như trong (1), khi tôi có thể? Tôi đã thấy điều đó được thực hiện trong nhiều ví dụ trên Internet.
    Chỉnh sửa : Khi tôi nói "sử dụng grep trên một thư mục", tôi có nghĩa là "tìm kiếm trong tất cả các tệp trong thư mục đó ngoại trừ các thư mục con của nó". Tôi tin rằng đây là những gì grep làm khi bạn chuyển một thư mục đến nó thay cho một tệp. Tôi có sai không?

  2. Xin vui lòng cho tôi một lời giải thích về hoạt động của grepnó sẽ giải thích hành vi của các lệnh trong (2).
    Chỉnh sửa : Hãy để tôi được cụ thể hơn. Tại sao sử dụng ký tự đại diện để chỉ định nhiều tệp để tìm kiếm để làm việc cùng .bash*và không có *hoặc thậm chí./* ?

  3. Làm cách nào tôi có thể tìm kiếm tất cả các tệp trong một thư mục (chứ không phải thư mục con của nó) bằng cách sử dụng grep?


Ngoài ra, bạn đang dựa vào các ký tự mở rộng vỏ như *, được gọi là Globing. Globbing không bao gồm tên tệp bắt đầu bằng một dấu chấm .bashrcnhư tiêu chuẩn. Bạn có thể đặt các tùy chọn shell để nó sẽ bao gồm các tệp này, nhưng bạn có thể gặp rắc rối nếu bạn không biết mình đang làm gì. Một hướng dẫn tốt để hiểu sự hả hê có thể được tìm thấy ở đây mywiki.wooledge.org/glob
Arronical

Tôi không biết tại sao, nhưng tôi đã luôn thực hiện toàn cầu trên các tệp ẩn và nó luôn hoạt động. Tôi đã không thay đổi bất kỳ thiết lập hoặc một cái gì đó. Như tôi đã chỉ ra trong (2), nó cũng hoạt động với grep "string" .bash*.
John Red

Xin lỗi, ví dụ cuối cùng của tôi là không chính xác. Bạn cũng có thể tìm kiếm trong các tệp ẩn và loại bỏ "là một thư mục" vì về mặt kỹ thuật Linux xem các thư mục là một loại tệp khác. Lệnh sẽ là: grep "string" * .* 2>/dev/nullhoặcgrep -s "string" * .*
Terrance

Câu trả lời:


40

Trong Bash, một quả cầu sẽ không mở rộng thành các tệp ẩn, vì vậy nếu bạn muốn tìm kiếm tất cả các tệp trong một thư mục, bạn cần chỉ định các tệp ẩn .*và không ẩn *.

Để tránh các lỗi "Là thư mục", bạn có thể sử dụng -d skip, nhưng trên hệ thống của tôi, tôi cũng gặp lỗi grep: .gvfs: Permission denied , vì vậy tôi khuyên bạn nên sử dụng -s, ẩn tất cả các thông báo lỗi.

Vì vậy, lệnh bạn đang tìm kiếm là:

grep -s "string" * .*

Nếu bạn đang tìm kiếm tập tin trong một thư mục khác:

grep -s "string" /path/to/dir/{*,.*}

Một tùy chọn khác là sử dụng dotglobtùy chọn shell, sẽ tạo ra một tập hợp bao gồm các tập tin ẩn.

shopt -s dotglob
grep -s "string" *

Đối với các tệp trong thư mục khác:

grep -s "string" /path/to/dir/*

Ai đó đã đề cập rằng tôi không nên nhận lỗi này. Họ có thể đúng - tôi đã đọc một số nhưng không thể tự mình làm được.


Có bất kỳ lý do cho không gian giữa *.*?
Hashim

2
@Hashim So sánh đầu ra echo * .*echo *.*chạy trong thư mục chính của bạn, và sự khác biệt sẽ là rõ ràng. Nếu không thì LMK và tôi sẽ giải thích nó.
wjandrea

Thật thú vị, vì vậy echo *hiển thị các tệp và thư mục echo *.*không bị ẩn, echo .*hiển thị các tệp không bị ẩn, hiển thị tất cả các tệp và echo * .*hiển thị tất cả các tệp và thư mục. Nhưng tại sao lý do cho không gian giữa hai trong trường hợp sau? Nó cảm thấy lộn xộn với tôi. Không có cách nào để kết hợp cả hai để có được kết quả giống nhau? Hoặc nếu không có một lời giải thích cú pháp về lý do tại sao hai cần phải được tách ra ở đây, hoặc là * .*một trường hợp ngoại lệ?
Hashim

1
@Hashim Tôi không chắc bạn đã đưa ra kết luận như thế nào, vì vậy hãy để tôi giải thích. Đầu tiên, thư mục là các tập tin trong bối cảnh này. Trong các khối, *đại diện cho tất cả các tệp không bị ẩn (ví dụ tên tệp không bắt đầu bằng dấu chấm); .*đại diện cho tất cả các file ẩn (tức là tên tập tin mà ta bắt đầu với một dấu chấm); và *.*đại diện cho tất cả các tệp không ẩn có chứa dấu chấm. Trong echo * .*, hai quả cầu phải tách biệt vì chúng là những khối khác nhau: một cho không ẩn, một cho ẩn. Mặc dù như tôi đã viết trong câu trả lời của mình, bạn có thể tạo *các tệp ẩn bằng cách bật dotglobtùy chọn shell.
wjandrea

1
Việc sử dụng *.*là phổ biến trên Windows (DOS) như một cách để liệt kê tất cả các tệp nhưng trên * nix sẽ chỉ bao gồm các tệp có dấu chấm trong đó, vì vậy nó không có ý nghĩa gì đối với * nix. Thay vào đó, bạn sử dụng *để liệt kê tất cả các tệp ngoại trừ các tệp bị ẩn và .*liệt kê các tệp bị ẩn.
thomasrutter

10

Bạn cần -d skiptùy chọn thêm vào.

  1. Grep đang tìm kiếm bên trong các tập tin. Bạn có thể tìm kiếm đệ quy, như bạn đã nói, nếu bạn muốn tìm kiếm các tập tin bên trong một thư mục.

  2. Theo mặc định, grep sẽ đọc tất cả các tệp và nó phát hiện các thư mục. Bởi vì theo mặc định, bạn không xác định phải làm gì với các thư mục với -dtùy chọn, nó đưa ra lỗi đầu ra.

  3. Tìm kiếm ngay trong thư mục mẹ sẽ là `grep -d bỏ qua" chuỗi "./*


Để biết thêm thông tin về grep, xem man grep.
nặc

(a) Xin vui lòng xem chỉnh sửa. (b) Sử dụng -d skipkhông hoạt động; về cơ bản nó giống như -s; Ngoài ra, xem chỉnh sửa. (c) Không, grep -d skip "string" ./*cũng không hoạt động.
John Red

7

Đồng hồ cũ có thể sẽ làm điều này:

find . -type f -print0 | xargs -0 grep "string"

3
Tại sao không find . -type f -exec grep string {} +?
wchargein

5
Bạn cũng muốn -maxdepth 1.
wchargein

@wchargein: nếu bạn muốn tên tệp ở đầu ra khi chỉ có một tệp tôi nghĩ bạn muốnfind . -type f -maxdepth 1 -exec grep string /dev/null {} +
Gregory Nisbet

1
@GregoryNisbet: Chỉ cần chuyển qua -Hgrep.
wchargein

2

Đọc lại - bạn muốn grep các tệp trong một cấp thư mục con, nhưng không lặp lại mặc dù tất cả các thư mục con?

grep forthis  *  */*

Hoặc nếu bạn không muốn các tệp trong thư mục hiện tại

grep forthis  */*

Lưu ý điều này sẽ không tìm thấy các thư mục bắt đầu bằng một dấu chấm.

grep forthis  .*/*    */*   

nên làm công việc đó

Cũng có -maxdepth-mindepthcác tham số hạn chế có sẵn cho findlệnh.


Sẽ không grep forthis */*tìm kiếm các tập tin cả trong thư mục hiện tại và một thư mục xuống?
Hashim

@Hashim không phải là chủ yếu - cos */*chỉ khớp mọi thứ với một dấu gạch chéo. Nếu bạn có một tệp có tên a/btrong thư mục hiện tại thì `* / * sẽ khớp với tệp đó.
Criggie

0

Dưới đây là một ví dụ để bỏ qua các thư mục mà không bỏ qua tất cả các lỗi:

grep --directories='skip' 'searchString' *
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.