Làm cách nào để loại trừ / bỏ qua các tập tin và thư mục bị ẩn trong một tìm kiếm được nhúng ký tự đại diện?


119

Bắt đầu từ (chú ý các ký tự đại diện trước và sau "một số văn bản")

find . -type f -name '*some text*'

Làm thế nào người ta có thể loại trừ / bỏ qua tất cả các tập tin và thư mục ẩn?

Tôi đã googling quá lâu , tình cờ thấy một số -prune và! (dấu chấm than), nhưng không có ví dụ phù hợp (và phân tích) mà chỉ hoạt động .

Đường ống | để grepsẽ là một lựa chọn và tôi cũng muốn chào đón những ví dụ về điều đó; nhưng chủ yếu tôi quan tâm đến một lớp lót ngắn gọn (hoặc một vài lớp lót độc lập, minh họa các cách khác nhau để đạt được cùng một mục tiêu dòng lệnh) chỉ sử dụng find.

ps: Tìm các tệp trong linux và loại trừ các thư mục cụ thể có vẻ liên quan chặt chẽ, nhưng a) chưa được chấp nhận và b) có liên quan nhưng khác biệt và khác biệt, nhưng c) có thể cung cấp nguồn cảm hứng và giúp xác định sự nhầm lẫn!

Biên tập

find . \( ! -regex '.*/\..*' \) -type f -name "whatever", làm. Regex tìm kiếm "bất cứ thứ gì, sau đó là dấu gạch chéo, rồi dấu chấm, rồi bất cứ thứ gì" (nghĩa là tất cả các tệp và thư mục ẩn bao gồm cả thư mục con của chúng) và "!" phủ nhận regex.


Không giúp gì với những gì bạn đã hỏi trong bản chỉnh sửa của bạn nhưng hãy xem câu hỏi của tôi và câu trả lời của nó ở đây: unix.stackexchange.com/q/69164/15760 và cả liên kết trong câu trả lời.

Câu trả lời:


134

Điều này in tất cả các tệp là hậu duệ của thư mục của bạn, bỏ qua các tệp và thư mục ẩn:

find . -not -path '*/\.*'

Vì vậy, nếu bạn đang tìm kiếm một tệp có some texttên của nó và bạn muốn bỏ qua các tệp và thư mục ẩn, hãy chạy:

find . -not -path '*/\.*' -type f -name '*some text*'

Giải trình:

Các -pathtùy chọn chạy kiểm tra một mô hình chống lại toàn bộ chuỗi con đường. *là ký tự đại diện, /là dấu phân cách thư mục, \.là dấu chấm (nó phải được thoát để tránh ý nghĩa đặc biệt) và *là một ký tự đại diện khác. -notcó nghĩa là không chọn các tệp phù hợp với thử nghiệm này.

Tôi không nghĩ rằng findnó đủ thông minh để tránh đệ quy tìm kiếm các thư mục ẩn trong lệnh trước đó, vì vậy nếu bạn cần tốc độ, -prunethay vào đó, hãy sử dụng , như thế này:

 find . -type d -path '*/\.*' -prune -o -not -name '.*' -type f -name '*some text*' -print

Lưu ý với cái cuối cùng mà bạn cần -printở cuối! Ngoài ra, không chắc chắn nếu -name '\.*' would be more efficient instead of -path` (vì đường dẫn đang tìm kiếm các đường dẫn phụ, nhưng chúng sẽ bị cắt bỏ)
artfulrobot

Ý nghĩa đặc biệt của .bối cảnh này là gì?
frostschutz

@frostschutz Dấu chấm sau findcó nghĩa là thư mục hiện tại: findsẽ xem xét tất cả các tệp và thư mục trong thư mục hiện tại. Đối số sau pathlà một biểu thức chính quy, trong đó một dấu chấm thường có nghĩa là "bất kỳ ký tự nào", để làm cho nó có nghĩa là một dấu chấm theo nghĩa đen, chúng ta phải thoát nó bằng dấu gạch chéo ngược. Đối số sau đó -name không phải là một biểu thức thông thường, nhưng nó mở rộng các ký tự đại diện giống ?*giống như một cái vỏ.
Flimm

2
@frostschutz Thật ra, khi nghĩ về nó, tôi có thể sai về .việc có ý nghĩa đặc biệt.
Flimm

1
@Flimm yup, không cần phải trốn thoát .. Theo như tôi biết, chỉ những cần phải được thoát: *, ?, và [].
thdoan

10

Đây là một trong số ít phương tiện loại trừ các tệp chấm cũng hoạt động chính xác trên BSD, Mac và Linux:

find "$PWD" -name ".*" -prune -o -print
  • $PWD in đường dẫn đầy đủ đến thư mục hiện tại để đường dẫn không bắt đầu bằng ./
  • -name ".*" -prune khớp với bất kỳ tệp hoặc thư mục nào bắt đầu bằng dấu chấm và sau đó không hạ xuống
  • -o -printcó nghĩa là in tên tệp nếu biểu thức trước đó không khớp với bất cứ thứ gì. Sử dụng -printhoặc -print0khiến tất cả các biểu thức khác không được in theo mặc định.

Vui lòng giải thích / giải thích về "phức tạp đáng báo động"; các câu trả lời đã được đưa ra và câu trả lời của bạn dường như đưa ra bằng chứng ngược lại ...?
hấp dẫn về natty

2
"phức tạp đáng báo động" có lẽ là quá mức. Tôi viết lại câu trả lời để đi đến điểm chính. Tôi nghĩ rằng câu trả lời tôi đã đăng là khó hiểu và khó nhìn nếu không đọc kỹ trang người đàn ông. Nếu bạn chỉ sử dụng GNU find thì có nhiều giải pháp khả thi hơn.
eradman 28/03/2016

-o ... -printlà hữu ích. Đối với việc sử dụng của tôi, bây giờ tôi có find ... '!' -name . -name '.*' -prune -o ... -print, thuận tiện hơn bao gồm cả $ PWD.
Roger Pate

4
find $DIR -not -path '*/\.*' -type f \( ! -iname ".*" \)

Không bao gồm tất cả các thư mục ẩn và các tệp ẩn dưới $ DIR


Đây là câu trả lời hoàn hảo. Nó đệ quy tìm tất cả các tệp nhưng loại trừ các chi tiết đơn hàng cho các thư mục và các tệp ẩn. Cảm ơn!
KyleFarris

2

Câu trả lời ban đầu tôi đã đăng là "chỉnh sửa" cho câu hỏi ban đầu của tôi ở trên:

find . \( ! -regex '.*/\..*' \) -type f -name "whatever", làm. Regex tìm kiếm "bất cứ thứ gì, sau đó là dấu gạch chéo, rồi dấu chấm, rồi bất cứ thứ gì" (nghĩa là tất cả các tệp và thư mục ẩn bao gồm cả thư mục con của chúng) và "!" phủ nhận regex.


Tương tự, nhưng chỉ dành cho thư mục hiện tại:find . \( ! -regex './\..*' \) -type f -maxdepth 1 -print
phyatt 22/03/2017

2

Bạn không phải sử dụng findcho điều đó. Chỉ cần sử dụng globalstar trong shell it-self, như:

echo **/*foo*

hoặc là:

ls **/*foo*

trong đó **/đại diện cho bất kỳ thư mục đệ quy và *foo*bất kỳ tệp nào có footên của nó.

Theo mặc định, việc sử dụng lssẽ in tên tệp không bao gồm các tệp và thư mục ẩn.

Nếu bạn không kích hoạt tính năng Globing, hãy thực hiện bằng cách shopt -s globstar.

Lưu ý: Một tùy chọn Globing mới hoạt động trong Bash 4, zsh và các shell tương tự.


Thí dụ:

$ mkdir -vp a/b/c/d
mkdir: created directory 'a'
mkdir: created directory 'a/b'
mkdir: created directory 'a/b/c'
mkdir: created directory 'a/b/c/d'
$ touch a/b/c/d/foo a/b/c/d/bar  a/b/c/d/.foo_hidden a/b/c/d/foo_not_hidden
$ echo **/*foo*
a/b/c/d/foo  a/b/c/d/foo_not_hidden

5
Bạn không cần lsđiều đó! echo **/*foo*
Kevin Cox

@kenorb (và @ kevin-cox). Bạn có thể dài dòng hơn một chút? Tại sao globalstar (= *) hoạt động ở đây và như thế nào? Dấu gạch chéo / làm gì?
hấp dẫn về

@nuttyaboutnatty /có nghĩa là thư mục, nó tách các thư mục khỏi tên tệp. *về cơ bản đại diện cho tất cả mọi thứ.
kenorb

@kenorb yes-but: làm thế nào mà một-liner giúp với câu hỏi ban đầu?
hấp dẫn về natty

1
@nuttyaboutnatty Làm rõ và thêm ví dụ. Nó giúp bằng cách tìm các tập tin bỏ qua cái bị ẩn.
kenorb

1

Câu trả lời của @ Flimm là tốt, đặc biệt bởi vì nó ngăn không cho tìm thấy giảm dần vào các thư mục ẩn . Tôi thích đơn giản hóa này:

Nói chung để loại trừ tất cả các đường dẫn ẩn (tệp thông thường, thư mục, v.v.):

find <start-point> -path '*/.*' -prune -o <expression> -print

Ví dụ: sử dụng thư mục làm việc của bạn làm điểm bắt đầu và -name '*some text*'làm biểu thức:

find . -path '*/.*' -prune -o -name '*some text*' -print

Trái ngược với những gì câu trả lời của @ Flimm gợi ý, không có tập tin ẩn hoặc thư mục ẩn nào là trường hợp đơn giản. Các -path '*/.*'biểu thức là đúng đối với bất kỳ con đường (tập tin thông thường, thư mục, vv) mà có một .ngay sau khi tách tập tin của bạn, /. Vì vậy, dòng này sẽ cắt tỉa cả các tập tin và thư mục ẩn.

Cho phép các tệp ẩn trong khi loại trừ các thư mục ẩn là trường hợp cần thêm bộ lọc. Đây là nơi bạn sẽ bao gồm -type dtrong biểu thức được cắt tỉa.

find <start-point> -type d -path '*/.*' -prune -o <expression> -print 

Ví dụ:

find . -type d -path '*/.*' -prune -o -name '*some text*' -print

Trong trường hợp -type d -path '*/.*'này truechỉ dành cho các thư mục, và vì vậy chỉ có các thư mục được cắt tỉa.


0

findcó các công tắc logic gọn gàng như -and-notbạn có thể sử dụng chúng theo lợi thế của mình để tìm một tệp phù hợp với hai quy tắc như vậy:

$ touch non_hidden_file.txt .hidden_file.txt somethings/.another_hidden_file.txt                                                 

$ find . -type f -name '*hidden_file*' -and \( -not -name ".*" \)                            
./non_hidden_file.txt

Như bạn có thể thấy, findsử dụng hai quy tắc -name '*hidden_file*'-and \( -not -name ".*" \)để tìm những tên tệp phù hợp với cả hai điều kiện - tên tệp có hidden_filetrong đó nhưng không có dấu chấm dẫn đầu. Lưu ý dấu gạch chéo phía trước dấu ngoặc đơn - chúng được sử dụng để xác định dấu ngoặc đơn là findđối số thay vì xác định dấu phụ (nghĩa là dấu ngoặc đơn có nghĩa khác nếu không có dấu gạch chéo)


0
$ pwd
/home/victoria

$ find $(pwd) -maxdepth 1 -type f -not -path '*/\.*' | sort
/home/victoria/new
/home/victoria/new1
/home/victoria/new2
/home/victoria/new3
/home/victoria/new3.md
/home/victoria/new.md
/home/victoria/package.json
/home/victoria/Untitled Document 1
/home/victoria/Untitled Document 2

$ find . -maxdepth 1 -type f -not -path '*/\.*' | sed 's/^\.\///g' | sort
new
new1
new2
new3
new3.md
new.md
package.json
Untitled Document 1
Untitled Document 2

Ghi chú:

  • . : thư mục hiện tại
  • loại bỏ -maxdepth 1để tìm kiếm đệ quy
  • -type f: tìm tệp, không phải thư mục ( d)
  • -not -path '*/\.*' : không trở về .hidden_files
  • sed 's/^\.\///g': xóa phần được thêm vào ./khỏi danh sách kết quả
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.