Xóa tất cả các tệp ngoại trừ một số từ một thư mục


215

Khi sử dụng sudo rm -r, làm cách nào tôi có thể xóa tất cả các tệp, ngoại trừ các mục sau:

textfile.txt
backup.tar.gz
script.php
database.sql
info.txt

5
Nghe có vẻ như một câu hỏi cho unix.stackexchange.com
Jason

1
Có 2 cách để đọc câu hỏi này và các câu trả lời hiện có bao gồm cả hai cách hiểu: EITHER: (a) giữ các tệp có tên được chỉ định trực tiếp trong thư mục đích và - như rm -rngụ ý - xóa mọi thứ khác, kể cả thư mục con - ngay cả khi chúng chứa tập tin với tên được chỉ định; HOẶC: (b) duyệt toàn bộ cây con của thư mục đích và, trong mỗi thư mục, xóa tất cả các tệp trừ những tệp có tên được liệt kê.
mkuity0

Câu trả lời:


219
find [path] -type f -not -name 'textfile.txt' -not -name 'backup.tar.gz' -delete

Nếu bạn không chỉ định -type ffind cũng sẽ liệt kê các thư mục mà bạn có thể không muốn.


Hoặc một giải pháp tổng quát hơn bằng cách sử dụng kết hợp rất hữu ích find | xargs:

find [path] -type f -not -name 'EXPR' -print0 | xargs -0 rm --

ví dụ: xóa tất cả các tệp không txt trong thư mục hiện tại:

find . -type f -not -name '*txt' -print0 | xargs -0 rm --

Sự kết hợp print0-0là cần thiết nếu có khoảng trắng trong bất kỳ tên tệp nào cần được xóa.


2
có vẻ như xargs có giới hạn kích thước văn bản
frazras

26
để xóa nhiều mẫu:find . -type f -not -name '*ignore1' -not -name '*ignore2' | xargs rm
Siwei Shen 申思维 18/03/13

5
Còn thư mục thì sao? Nó sẽ xóa tất cả các tập tin, nhưng nó có xóa các thư mục không?!
orezvani

31
Thay vì "| xargs rm", find sẽ lấy tham số -delete.
Emil Stenström

1
thay vì -print0 | xargs -0 rm --bạn chỉ có thể-delete
Andy

150
rm !(textfile.txt|backup.tar.gz|script.php|database.sql|info.txt)

Extglob (Kết hợp mẫu mở rộng) cần được bật trong BASH (nếu nó không được bật):

shopt -s extglob

2
Tôi nhận được "lỗi cú pháp gần mã thông báo bất ngờ` ('"khi tôi làm shopt -s extglob; rm -rf !(README|LICENSE). Có ai biết tại sao không?
Dennis

@nic Tôi không nhớ, xin lỗi. Tôi có thể đã kết thúc bằng cách sử dụng findvới -deletetùy chọn.
Dennis

Đây là giải pháp tốt nhất cho tôi và nó hoạt động theo mặc định trên Ubuntu 12.04.4 LTS của tôi mà không cần shopt
xtian

3
@nic, @Dennis: Lỗi cú pháp cho thấy rằng một cái gì đó KHÁC hơn bashđã được sử dụng, ví dụ dash, nơi extglobkhông được hỗ trợ. Tuy nhiên, trong một vỏ tương tác bash , lệnh C ALNG sẽ không hoạt động như đã nêu, mặc dù vì những lý do khác nhau. Tóm tắt của nó: thực hiện shopt -s extglobbởi ITSELF; ONCE THÀNH CÔNG ENABLED (xác minh với shopt extglob), thực thi rm -rf !(README|LICENSE). (Trong khi extglobchưa được bật, !(...)được đánh giá bằng cách mở rộng lịch sử TRƯỚC KHI các lệnh được thực thi; vì điều này có thể thất bại, lệnh NEITHER được thực thi và extglobkhông bao giờ được bật.)
mkuity0

2
@nic, @Dennis, @ mkuity0: Tôi gặp vấn đề tương tự với "lỗi cú pháp gần mã thông báo không mong muốn (" khi thực thi lệnh trong tệp .sh (#! / Bin / bash) nhưng không phải khi tôi đang chạy nó trong lệnh Giao diện dòng. Hóa ra ngoài việc shopt -s extglobchạy trong giao diện dòng lệnh, tôi phải chạy lại nó trong tệp tập lệnh của mình. Điều này đã giải quyết vấn đề cho tôi.
Ahresse

41

find . | grep -v "excluded files criteria" | xargs rm

Điều này sẽ liệt kê tất cả các tệp trong thư mục hiện tại, sau đó liệt kê tất cả những tệp không phù hợp với tiêu chí của bạn (hãy cẩn thận với tên thư mục phù hợp) và sau đó xóa chúng.

Cập nhật : dựa trên chỉnh sửa của bạn, nếu bạn thực sự muốn xóa mọi thứ khỏi thư mục hiện tại ngoại trừ các tệp bạn đã liệt kê, điều này có thể được sử dụng:

mkdir /tmp_backup && mv textfile.txt backup.tar.gz script.php database.sql info.txt /tmp_backup/ && rm -r && mv /tmp_backup/* . && rmdir /tmp_backup

Nó sẽ tạo một thư mục sao lưu /tmp_backup(bạn đã có quyền root, phải không?), Di chuyển các tệp bạn đã liệt kê vào thư mục đó, xóa đệ quy mọi thứ trong thư mục hiện tại (bạn có biết rằng bạn đang ở đúng thư mục không?), Di chuyển trở lại thư mục hiện tại mọi thứ từ /tmp_backupvà cuối cùng, xóa /tmp_backup.

Tôi chọn thư mục sao lưu để được root, bởi vì nếu bạn đang cố gắng xóa mọi thứ đệ quy từ root, hệ thống của bạn sẽ gặp vấn đề lớn.

Chắc chắn có nhiều cách thanh lịch hơn để làm điều này, nhưng cách này khá đơn giản.


2
Hoạt động cũng thực sự tốt với egrep, ví dụ: để làm sạch các tệp latex trung gian:find . | egrep -v "\.tex|\.bib" | xargs rm
mtsz

lệnh tuyệt vời! để xóa thư mục, chỉ cần thay đổi thành rm -r
Aris

1
Nếu bạn chỉ muốn xóa mọi thứ trong thư mục hiện tại ngoài các tiêu chí bị loại trừ: find . -maxdepth 1 | grep -v "exclude these" | xargs rm -rhoạt động nhanh hơn nhiều vì không cần phải đi sâu vào các thư mục không cần thiết.
billynoah

Re findpipe: vấn đề hiệu quả sang một bên (3 lệnh được sử dụng cho những gì findcó thể làm một mình), điều này sẽ không hoạt động như dự định với tên tệp có không gian nhúng và sẽ có khả năng xóa các tệp sai.
mkuity0

Một lệnh lưu trữ các tệp "sẽ được lưu" ở một vị trí khác ( /tmp_backup) sẽ không kết thúc tốt nếu nó bị gián đoạn từ góc nhìn của người dùng, tất cả các tệp đã biến mất, trừ khi họ biết phải tìm chúng ở đâu để lấy lại chúng . Vì lý do đó, tôi không ủng hộ loại chiến lược này.
Craig McQueen

20

Giả sử rằng các tệp có các tên đó tồn tại ở nhiều vị trí trong cây thư mục và bạn muốn giữ tất cả chúng:

find . -type f ! -regex ".*/\(textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt\)" -delete

19

Bạn có thể sử dụng biến môi trường GLOBIGNORE trong Bash.

Giả sử bạn muốn xóa tất cả các tệp trừ php và sql, thì bạn có thể làm như sau -

export GLOBIGNORE=*.php:*.sql
rm *
export GLOBIGNORE=

Đặt GLOBIGNORE như thế này bỏ qua php và sql từ các ký tự đại diện được sử dụng như "ls *" hoặc "rm *". Vì vậy, sử dụng "rm *" sau khi đặt biến sẽ chỉ xóa tệp txt và tar.gz.


6
+1; Một cách khác đơn giản hơn để thiết lập và khôi phục GLOBIGNOREbiến là sử dụng một lớp con:(GLOBIGNORE='*.php:*.sql'; rm *)
mkuity0

19

Tôi thích sử dụng danh sách truy vấn phụ:

rm -r `ls | grep -v "textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt"`

-v, --invert-match chọn các dòng không khớp

\| Dấu phân cách


1
Giải pháp tao nhã
Joshua Salazar

9

Vì không ai đề cập đến nó:

  • sao chép các tập tin bạn không muốn xóa ở nơi an toàn
  • xóa tất cả các tập tin
  • di chuyển các tập tin sao chép trở lại vị trí

2
Nó phức tạp hơn vì bạn phải chăm sóc các quyền sau khi bạn sao chép lại.
Romulus

2
@RemusAvram Bạn có thể sử dụng các công tắc thích hợp có cphoặc rsyncđể giữ quyền. Dù sao, đây chỉ là một phương pháp thay thế (được đưa ra như một gợi ý) có vị trí của nó ở đây, như là một câu trả lời cho OP.
gniourf_gniourf

Điều này có thể không phù hợp trong nhiều tình huống trong đó các tệp được giữ lại đang được các quy trình khác sử dụng tích cực. Nó cũng cồng kềnh của các tệp bị loại bỏ chỉ là một tập hợp con nhỏ và một số lượng lớn các tệp có liên quan.
tiền mã hóa

@codeforester: chắc chắn rồi. Nhưng có những tình huống phù hợp, mặc dù ... thực tế tôi không thực sự thấy ý kiến ​​của bạn :).
gniourf_gniourf

6

Bạn có thể viết một vòng lặp for cho ...%)

for x in *
do
        if [ "$x" != "exclude_criteria" ]
        then
                rm -f $x;
        fi
done;

6

Một chút muộn cho OP, nhưng hy vọng hữu ích cho bất kỳ ai đến đây muộn hơn bởi google ...

Tôi tìm thấy câu trả lời của @awi và nhận xét về -delete bởi @Jamie Bullock thực sự hữu ích. Một tiện ích đơn giản để bạn có thể thực hiện việc này trong các thư mục khác nhau bỏ qua các tên / loại tệp khác nhau mỗi lần với kiểu gõ tối thiểu:

rm_except (hoặc bất cứ điều gì bạn muốn đặt tên cho nó)

#!/bin/bash

ignore=""

for fignore in "$@"; do
  ignore=${ignore}"-not -name ${fignore} "
done

find . -type f $ignore -delete

ví dụ: để xóa mọi thứ trừ tệp văn bản và foo.bar:

rm_except *.txt foo.bar 

Tương tự như @mishunika, nhưng không có mệnh đề if.


5

Nếu bạn đang sử dụng zshmà tôi rất khuyến khích.

rm -rf ^file/folder pattern to avoid

Với extended_glob

setopt extended_glob
rm -- ^*.txt
rm -- ^*.(sql|txt)

4

Đang thử nó hoạt động với:

rm -r !(Applications|"Virtualbox VMs"|Downloads|Documents|Desktop|Public)

nhưng tên với không gian là (như mọi khi) khó khăn. Đã thử cũng Virtualbox\ VMsthay vì dấu ngoặc kép. Nó luôn xóa thư mục đó ( Virtualbox VMs).


KHÔNG làm việc cho các tập tin. rm !(myfile.txt)xóa tất cả bao gồmmyfile.txt
khaverim

nên thực hiện shopt -s extglobđầu tiên như @ pl1nk đã chỉ ra
zhuguowei

Vâng, điều rất quan trọng để kích hoạt tính năng mở rộng toàn cầu ( extglob ) trong bash, tôi đang thực hiện việc này trong cơ sở hàng ngày, qua một vài máy Mac trong phòng thí nghiệm: shopt -s extglobvà sau đó cd /Users/alumno/và cuối cùng là rm -rf !(Applications|Virtualbox*VMs|Downloads|Documents|Desktop|Public|Library) đọc về mở rộng toàn cầu ở đây
juanfal

4

Chỉ:

rm $(ls -I "*.txt" ) #Deletes file type except *.txt

Hoặc là:

rm $(ls -I "*.txt" -I "*.pdf" ) #Deletes file types except *.txt & *.pdf

Điều này không được khuyến khích. Phân tích lsđầu ra có thể trở thành một vấn đề là. Xem tại đây để biết thông tin chi tiết.
RJ

2

Làm cho các tập tin bất biến. Thậm chí không root sẽ được phép xóa chúng.

chattr +i textfile.txt backup.tar.gz script.php database.sql info.txt
rm *

Tất cả các tập tin khác đã bị xóa.
Cuối cùng, bạn có thể thiết lập lại chúng có thể thay đổi.

chattr -i *

0

Điều này tương tự như nhận xét từ @ siwei-shen nhưng bạn cần -ocờ để thực hiện nhiều mẫu. Các -olá cờ tượng trưng cho 'hoặc'

find . -type f -not -name '*ignore1' -o -not -name '*ignore2' | xargs rm


0

Bạn có thể làm điều này với hai chuỗi lệnh. Trước tiên, xác định một mảng với tên của các tệp bạn không muốn loại trừ:

files=( backup.tar.gz script.php database.sql info.txt )

Sau đó, lặp qua tất cả các tệp trong thư mục bạn muốn loại trừ, kiểm tra xem tên tệp có nằm trong mảng bạn không muốn loại trừ hay không; Nếu không thì xóa tập tin.

for file in *; do
  if [[ ! " ${files[@]} " ~= "$file"  ]];then
    rm "$file"
  fi
done

So sánh regex là không chính xác - nó sẽ giữ bất kỳ tệp nào có tên là một chuỗi con của một trong các tệp được bảo vệ (mặc dù các không gian xung quanh phần nào giảm thiểu điều đó; nhưng tên tệp có thể chứa khoảng trắng). Bạn nên thu thập một mảng của tất cả các tệp, sau đó trừ các tệp bạn muốn loại trừ khỏi mảng đó, sau đó xóa các tệp còn lại.
tripleee

-1

Vì chưa ai đề cập đến điều này, trong một trường hợp cụ thể:

OLD_FILES=`echo *`
... create new files ...
rm -r $OLD_FILES

(hoặc chỉ rm $OLD_FILES)

hoặc là

OLD_FILES=`ls *`
... create new files ...
rm -r $OLD_FILES

Bạn có thể cần sử dụng shopt -s nullglobnếu một số tệp có thể ở đó hoặc không ở đó:

SET_OLD_NULLGLOB=`shopt -p nullglob`
shopt -s nullglob
FILES=`echo *.sh *.bash`
$SET_OLD_NULLGLOB

không có nullglob, echo *.sh *.bashcó thể cung cấp cho bạn "a.sh b.sh * .bash".

(Đã nói tất cả, bản thân tôi thích câu trả lời này , mặc dù nó không hoạt động trong OSX)


Câu trả lời hiện có của Leonardo Hermoso thực hiện điều này với ít lỗi hơn. Điều này sẽ thất bại cho tên tệp có khoảng trắng; sử dụng một mảng một cách tao nhã giải quyết vấn đề cụ thể đó (và cũng ít tránh được việc sử dụng chữ hoa cho các biến riêng tư của mình, điều này thường được tránh).
tripleee

-3

Thay vì thực hiện một lệnh trực tiếp, vui lòng di chuyển các tệp cần thiết vào thư mục tạm thời bên ngoài thư mục hiện tại. Sau đó xóa tất cả các tập tin bằng cách sử dụng rm *hoặc rm -r *.

Sau đó di chuyển các tập tin cần thiết vào thư mục hiện tại.


Điều này có thể không phù hợp trong nhiều tình huống trong đó các tệp được giữ lại đang được các quy trình khác sử dụng tích cực. Nó cũng cồng kềnh của các tệp bị loại bỏ chỉ là một tập hợp con nhỏ và một số lượng lớn các tệp có liên quan.
tiền mã hóa

-3

Xóa mọi thứ loại trừ file.name:

ls -d /path/to/your/files/* |grep -v file.name|xargs rm -rf

2
Điều này sẽ thất bại khủng khiếp và có thể gây mất dữ liệu nếu thư mục / tệp của bạn có khoảng trắng hoặc ký tự bất thường. Bạn không bao giờ nên phân tích ls. mywiki.wooledge.org/ParsingLs
RJ
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.