Unix - xóa các tập tin và thư mục không bao gồm THỰC HIỆN


10

Gần đây tôi đã phải đối mặt với nhiệm vụ xóa tất cả các tệp / thư mục trong một thư mục không bao gồm những tệp phù hợp với một mẫu cụ thể. Vì vậy, tôi đã tạo ra một lệnh unix một dòng để thực hiện công việc. Nó phải chỉ là một dòng? Tôi cho là không, nhưng nó chắc chắn mát hơn theo cách đó!

Trong khi vấn đề khá đơn giản, tôi hơi ngạc nhiên về sự phức tạp của giải pháp của mình. Đây là lệnh tôi đã sử dụng; LƯU Ý: đây là một giải pháp kém vì nó không xử lý tên tệp có chứa các ký tự nguồn cấp dữ liệu (điều này không quan trọng trong tình huống của tôi).

ls | grep -v PATTERN | xargs -n1 -IREPLACE rm -rf REPLACE

Tôi đã không sử dụng lệnh "find" vì tôi không muốn lặp lại vào các thư mục khớp với MẪU. Ví dụ, hãy xem xét cấu trúc tệp sau:

file_foo.txt
first_dir
  |
  +--> contents
  +--> ...
foo_dir
  |
  +--> anotherfile.txt
  +--> morefiles.log
foo_file.txt
somefile.txt

Sử dụng mẫu "foo" chỉ phải xóa "first_dir" (và tất nhiên đó là nội dung) và "somefile.txt" ( không phải "Anotherfile.txt" hoặc "morefiles.log").

Câu hỏi, có cách nào tốt hơn (thanh lịch và chính xác hơn) để thực hiện điều này?


EDIT:
Gần đây tôi đã nhận thấy rằng "tìm" có thể là một lựa chọn tốt hơn :

find * -maxdepth 0 ! -name PATTERN -print0 | xargs -0n1 rm -rf

Giải pháp này xử lý chính xác các đường dẫn chứa các ký tự nguồn cấp dữ liệu.


EDIT: đã thay đổi "the_dir" sai thành "First_dir".
joxl

Câu trả lời:


10

Các ví dụ sau đây có echotiền tố để bạn có thể kiểm tra các mẫu trước khi thực sự sử dụng chúng. Hủy bỏ echođể kích hoạt rm -rf. Thay thế rm -riđể nhắc nhở xác nhận.

ksh có phần mở rộng kết hợp phủ định cho toàn cầu:

# ksh
echo rm -rf !(*foo*)

Cú pháp tương tự có sẵn trong bash nếu bạn đặt extglobtùy chọn:

# bash
shopt -s extglob
echo rm -rf !(*foo*)

zsh có cú pháp riêng cho việc này:

# zsh
setopt extended_glob
echo rm -rf ^*foo*

Nó cũng có thể sử dụng cú pháp kiểu ksh :

# zsh: ksh-style glob syntax
setopt ksh_glob no_bare_glob_qual
echo rm -rf !(*foo*)

# zsh: ksh-style glob syntax, adapted for the default bare_glob_qual option
setopt ksh_glob bare_glob_qual
echo rm -rf (!(*foo*))

Đơn giản, thanh lịch, xử lý các ký tự linefeed, (gần như) một dòng (Tôi đã thêm vào shopt -s extglobtệp .bashrc của mình, vì vậy bây giờ nó một lớp lót). Hoàn hảo! Tôi hứa một upvote ngay khi danh tiếng của tôi cho phép nó.
joxl

7

Đây là một findgiải pháp khác . Tôi không chắc điều này có bất kỳ lợi thế thực sự nào so với bạn, nhưng nó không cần xargsvà cho phép khả năng hiếm khi * mở rộng ra quá nhiều tên.

find . -maxdepth 1 ! -name PATTERN -type f -delete

Tôi cũng đã thêm -type fđể nó sẽ không xóa các thư mục.

Cảnh báo: -deletelà mạnh mẽ. Tôi đã cho một trong các quyền kiểm tra tệp 0 của tôi và lệnh trên đã xóa nó mà không do dự.


6
Kiểm tra trước. Thay thế -deletebằng -printđể xem nếu nó tìm thấy các tập tin bạn muốn. Nếu tất cả đều tốt, hãy sử dụng lịch sử lệnh (ví dụ: nhấn nút lên) để quay lại lệnh trước đó để đảm bảo rằng bạn đang làm việc với cùng các bộ lọc tìm.
Doug Harris

Đọc kỹ, lưu ý rằng tôi làm mong muốn root không xóa. Và find -deletesẽ không loại bỏ các thư mục không trống. Cũng lưu ý rằng find -maxdepth 1phù hợp "." (thư mục hiện tại) đó là thực sự xấu. Mặc dù tôi thích ý tưởng loại bỏ của bạn xargs, người ta có thể sử dụng find -execthay thế. find * -maxdepth 0 ! -name PATTERN -exec rm -rf '{}' \;
joxl

0

Bạn có thể sử dụng ví dụ tập lệnh rebol này http://askcodegeneration.com/keep-subversion/ thay vào đó dễ hiểu hơn nhiều và có thể quản lý tương tác người dùng như chọn và xác nhận thư mục:

delete-file: func[file][
    if/else none? find file "/.svn/" [
        delete file
    ][
        print ["keeping" file]
    ]
]
dir: request-dir
ans: ask rejoin ["Do you confirm " dir "? (Yes): "]
if (ans = "Yes") [
    foreach-file dir :delete-file
]
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.