Truyền nhiều thư mục vào tùy chọn -prune trong find


9

Tôi đang sử dụng findđể định vị và xóa các tập tin sao lưu nhưng muốn loại trừ các thư mục nhất định khỏi tìm kiếm. Các tên tập tin sao lưu có thể chấm dứt trong .bck, bak, ~, hoặcbackup .

Mã ví dụ làm việc tối thiểu (MWE) chỉ có ba thư mục để loại trừ là:

#! /bin/bash
find . -type d \( -path "./.*" -o -path "./Music" -o -path "./Documents" \) -prune -o -type f \( -name "*.bck" -o -name "*.bak" -o -name "*~" -o -name "*.backup" \) -print0 | xargs -0 --no-run-if-empty trash-put

Cú pháp \( -path "dir1" -o -path "dir2" ... -o -path "dirN" \) -prune có vẻ hơi lộn xộn, đặc biệt nếu có khoảng mười thư mục để loại trừ, mặc dù tôi chỉ hiển thị ba trong MWE.

Có cách nào thanh lịch hơn bằng cách sử dụng tệp đầu vào, với danh sách các thư mục bị loại trừ hoặc cấu trúc giống như mảng hoặc danh sách, có thể được nhấn vào dịch vụ không?

Tôi xin lỗi vì đã không rõ ràng hơn khi tôi viết câu hỏi ban đầu của tôi.

NB: trash-putlà một tiện ích di chuyển các tệp đến Trashcanthay vì xóa chúng [1].

[1]. https://github.com/andreafrancia/trash-cli

Câu trả lời:


4

Theo tôi biết, không có tùy chọn findđể đọc các mẫu từ một tệp. Một cách giải quyết dễ dàng là lưu các mẫu tôi muốn loại trừ trong một tệp và chuyển tệp đó làm đầu vào cho một đảo ngược grep. Ví dụ, tôi đã tạo các tệp và thư mục sau:

$ tree -a
.
├── a
├── .aa
├── .aa.bak
├── a.bck
├── b
├── .dir1
│   └── bb1.bak
├── dir2
│   └── bb2.bak
├── b.bak
├── c
├── c~
├── Documents
│   └── Documents.bak
├── exclude.txt
├── foo.backup
└── Music
    └── Music.bak

Nếu tôi hiểu ví dụ bạn được đăng một cách chính xác, bạn muốn di chuyển a.bck, .aa.bak, b.bak, c~, foo.backupdir2/bb2.bakvào thùng rác và nghỉ .aa.bak, .dir1/bb1.bak, Documents/Documents.bakMusic/Music.baknơi họ đang có. Do đó, tôi đã tạo tệp exclude.txtcó nội dung sau (bạn có thể thêm bao nhiêu tùy ý):

$ cat exclude.txt 
./.*/
./Music
./Documents

Tôi sử dụng ./.*/bởi vì tôi hiểu kết quả tìm kiếm ban đầu của bạn có nghĩa là bạn muốn di chuyển các tệp sao lưu ẩn ( .foo) trong thư mục hiện tại nhưng loại trừ mọi tệp sao lưu nằm trong các thư mục ẩn ( .foo/bar). Vì vậy, bây giờ tôi có thể chạy findlệnh và sử dụng grepđể loại trừ các tệp không mong muốn:

$ find . -type f | grep -vZf exclude.txt | xargs -0 --no-run-if-empty trash-put

Tùy chọn Grep:

   -v, --invert-match
          Invert  the  sense  of matching, to select non-matching
          lines.  (-v is specified by POSIX.)
   -f FILE, --file=FILE
          Obtain patterns from FILE, one  per  line.   The  empty
          file  contains  zero  patterns,  and  therefore matches
          nothing.  (-f is specified by POSIX.)
   -Z, --null
          Output a zero byte (the ASCII NUL character) instead of
          the  character  that normally follows a file name.  For
          example, grep -lZ outputs a zero byte after  each  file
          name  instead  of the usual newline.  This option makes
          the output unambiguous, even in the  presence  of  file
          names  containing  unusual  characters  like  newlines.
          This  option  can  be  used  with  commands  like  find
          -print0,  perl  -0,  sort  -z,  and xargs -0 to process
          arbitrary file names, even those that  contain  newline
          characters.

Tôi rất xin lỗi vì đã không rõ ràng. Vui lòng xem câu hỏi sửa đổi mà tôi hy vọng là rõ ràng hơn.
chandra

@framra xem câu trả lời cập nhật, cùng một ý tưởng chung, chi tiết khác nhau.
terdon

Cảm ơn bạn. Bạn đã trả lời câu hỏi của tôi rất rõ ràng và hoàn hảo cho mục đích của tôi. Tôi đã chấp nhận câu trả lời của bạn.
chandra

6

Với GNU find (nghĩa là dưới Linux hoặc Cygwin không được nhúng), bạn có thể sử dụng -regexđể kết hợp tất cả các -pathký tự đại diện này thành một biểu thức chính.

find . -regextype posix-extended \
     -type d -regex '\./(\..*|Music|Documents)' -prune -o \
     -type f -regex '.*(\.(bck|bak|backup)|~)' -print0 |
xargs -0 --no-run-if-empty trash-put

Với FreeBSD hoặc OSX, sử dụng -Ethay vì -regextype posix-extended.


Cảm ơn bạn cho một câu trả lời thay thế tuyệt vời. Thật xấu hổ khi tôi không thể chấp nhận hai câu trả lời.
chandra

2

Nhóm -path ... -prunethành một biểu thức kèm theo bằng \( ... \)cách sử dụng -o( hoặc ) logic.

find /somepath \( -path /a -prune -o \
                  -path /b -prune -o \
                  -path /c -prune \
               \) \
               -o -print

Ví dụ sẽ thư mục không lặp hoặc các tập tin bằng hoặc dưới /somepath/a, /somepath/b/somepath/c.

Dưới đây là một ví dụ cụ thể hơn bằng cách sử dụng nhiều hành động.

find / \( -path /dev -prune -o \
          -path /proc -prune -o \
          -path /sys -prune \
       \) \
       -o -printf '%p ' -exec cksum {} \;

1

Đây dường như là một câu hỏi vỏ hơn là một findcâu hỏi. Với một tệp chứa ( -name dir1 -o -name dir2 ) -prune(không có "\"!) Bạn chỉ cần làm điều này:

find ... $(< /path/to/file)

Không thay đổi cuộc gọi tìm chính nó (để eval find hoặc bằng cách thay đổi $ IFS), điều này hoạt động với các đường dẫn không chỉ có khoảng trắng.

Nếu bạn muốn giữ tập tin đơn giản hơn, bạn có thể viết một tập lệnh.

# file content
dir1
dir2
dir3

# script content
#!/bin/bash
file=/path/to/file
# file may be checked for whitespace here
grep '[^[:space:]]' "$file" | { empty=yes
  while read dir; do
    if [ yes = "$empty" ]; then
      echo -n "( "
      empty=no
    else
      echo -n " -o "
    fi
    echo -n "-name ${dir}"
  done
  if [ no = "$empty" ]; then
    echo -n " ) -prune"
  fi; }

Và sử dụng

find ... $(/path/to/script)

thay thế.


Tôi rất xin lỗi vì đã không rõ ràng. Vui lòng xem câu hỏi sửa đổi mà tôi hy vọng là rõ ràng hơn.
chandra

@chandra Tôi không thấy như thế nào câu hỏi của bạn là rõ ràng hơn cũng không làm tôi hiểu những gì có thể là một vấn đề với giải pháp của tôi (trừ replecement tầm thường của -namebằng path).
Hauke ​​Laging

Kịch bản của tôi ở trên hoạt động và làm những gì tôi muốn nó. Tôi chỉ đơn giản muốn biết liệu có cách nào gọn gàng hơn \( -path "dir1" -o -path "dir2" ... -o -path "dirN" \) -pruneđể loại trừ các thư mục nhất định khỏi tìm kiếm đệ quy findkhông. Tôi không tìm kiếm bất cứ thứ gì trong các tệp mà chỉ xóa một số tệp nhất định và tránh các thư mục nhất định trong đường dẫn tìm kiếm của tôi. Tôi cũng không hiểu kịch bản của bạn đang cố làm gì. Vì vậy, có vẻ như chúng ta có một thông tin sai lệch. Lấy làm tiếc. Hãy để chúng tôi để nó ở đó.
chandra
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.