Xóa tất cả các tệp ngoại trừ các tệp có phần mở rộng pdf trong một thư mục


50

Tôi có một thư mục chứa các mục sau:

x.pdf
y.zip
z.mp3
a.pdf

Tôi muốn xóa tất cả các tập tin ngoài x.pdfa.pdf. Làm thế nào để tôi làm điều này từ thiết bị đầu cuối? Không có thư mục con nên không cần đệ quy.

Câu trả lời:


63
cd <the directory you want>
find . -type f ! -iname "*.pdf" -delete
  • Lệnh đầu tiên sẽ đưa bạn đến thư mục mà bạn muốn xóa các tệp của mình
  • Lệnh thứ hai sẽ xóa tất cả các tệp trừ những .pdftệp kết thúc bằng tên tệp

Ví dụ: nếu có một thư mục được gọi temptrong thư mục nhà của bạn:

cd ~/temp

sau đó xóa các tập tin:

find . -type f ! -iname "*.pdf" -delete

Điều này sẽ xóa tất cả các tập tin ngoại trừ xyz.pdf.

Bạn có thể kết hợp hai lệnh này để:

find ~/temp -type f ! -iname "*.pdf" -delete

.là thư mục hiện tại. !có nghĩa là lấy tất cả các tập tin ngoại trừ những tập tin có .pdfở cuối. -type fchỉ chọn các tập tin, không phải thư mục. -deletecó nghĩa là xóa nó

LƯU Ý: lệnh này sẽ xóa tất cả các tệp (trừ tệp pdf nhưng bao gồm các tệp ẩn) trong thư mục hiện tại cũng như trong tất cả các thư mục con. !phải đến trước -name. đơn giản -namesẽ chỉ bao gồm .pdf, trong khi -inamesẽ bao gồm cả hai .pdf.PDF

Để chỉ xóa trong thư mục hiện tại và không trong thư mục con thêm -maxdepth 1:

find . -maxdepth 1 -type f ! -iname "*.pdf" -delete

Cảm ơn câu trả lời. Bạn có thể giúp tôi hiểu cú pháp một chút? .có nghĩa là "và"? !có nghĩa là "ngoại trừ" -namebiểu thị rằng bạn muốn loại trừ bởi một tham số tên và sau đó -deletelà hành động để thực hiện khi tìm kiếm? Vì vậy, nó tìm kiếm mọi thứ trừ "* .pdf" và xóa chúng? Hay tôi đã hiểu lầm?
jessenorton

.có nghĩa là thư mục hiện tại. !có nghĩa là lấy tất cả các tệp ngoại trừ tệp có .pdfở cuối. -deletecó nghĩa là xóa nó tôi đã rõ chưa
Edward Torvalds

@terdon Starkers nói rằng không có thư mục con. Chờ đợi chỉnh sửa câu trả lời của tôi để rộng hơn
Edward Torvalds

+1 Bạn nên bao gồm -maxdepth 1tham số để bắt đầu. Sau đó đề nghị xóa tham số trong trường hợp người ta muốn xóa đệ quy.
Tulains Córdova

3
điều này khiến tôi chú ý rằng chúng ta nên sử dụng -inamethay vì -namehoặc các tệp có .PDFphần mở rộng sẽ lướt qua.
muru

43

Với tính bashnăng mở rộng shell shell, bạn có thể xóa bất kỳ tệp nào có tiện ích mở rộng ngoài .pdfviệc sử dụng

rm -- *.!(pdf)

Theo ghi nhận của @pts, các --ký tự chỉ ra sự kết thúc của bất kỳ tùy chọn lệnh nào, làm cho lệnh an toàn trong trường hợp hiếm hoi của các tệp có tên bắt đầu bằng một -ký tự.

Nếu bạn muốn xóa các tệp mà không có bất kỳ tiện ích mở rộng nào cũng như các tiện ích mở rộng khác .pdf, thì như @DennisWilliamson chỉ ra, bạn có thể sử dụng

rm -- !(*.pdf)

Mở rộng toàn cầu nên được bật theo mặc định, nhưng nếu không, bạn có thể làm như vậy bằng cách sử dụng

shopt -s extglob

Đặc biệt nếu bạn có ý định sử dụng tập lệnh này trong tập lệnh, điều quan trọng cần lưu ý là nếu biểu thức không khớp với bất cứ thứ gì (nghĩa là nếu không có tệp không phải pdf trong thư mục), thì theo mặc định, toàn cầu sẽ được chuyển sang chưa được mở rộng cho rmlệnh, dẫn đến một lỗi như

rm: cannot remove `*.!(pdf)': No such file or directory

Bạn có thể sửa đổi hành vi mặc định này bằng nullglobtùy chọn shell, tuy nhiên điều đó có vấn đề riêng. Để thảo luận kỹ hơn, xem NullGlob - Greg's Wiki


Tiếp cận tốt hơn IMO.
Takkat

Còn những tập tin không có phần mở rộng thì sao? FWIW, trong zsh itrm *~*.pdf
Emil Jeřábek

1
Tôi sẽ đặt dấu chấm bên trong dấu ngoặc đơn.
Dennis Williamson

4
Ah, dấu hoa thị cũng nên đi vào bên trong : !(*.py). Ngoài ra, có lẽ, nếu OP chỉ muốn các tệp ".pdf" còn lại, thì các tệp không có phần mở rộng cũng sẽ bị xóa và không được bỏ qua.
Dennis Williamson

1
Cách tiếp cận này đơn giản và gọn gàng hơn câu trả lời được chấp nhận.
Peter

18

Xóa vào thùng rác :

$ cd <the directory you want>
$ gvfs-trash !(*.pdf)

Hoặc thông qua mvlệnh (nhưng theo cách này, bạn không thể khôi phục nó từ Thùng rác vì nó không ghi thông tin .trashinfo, vì vậy điều này có nghĩa là bạn đã di chuyển các tệp của mình đến đích như sau).

mv !(*.pdf) ~/.local/share/Trash/files

6
Cách tiếp cận này an toàn hơn nhiều so với sử dụng trực tiếp rm.
Seth

14

Cách tiếp cận đơn giản nhất: Tạo một thư mục khác ở đâu đó (nếu bạn chỉ xóa trong một thư mục, không đệ quy, nó thậm chí có thể là thư mục con); di chuyển tất cả .pdf ở đó; xóa mọi thứ khác; di chuyển trở lại của pdf; xóa thư mục trung gian.

Nhanh chóng, dễ dàng, bạn có thể thấy chính xác những gì bạn đang làm. Chỉ cần đảm bảo thư mục trung gian nằm trên cùng thiết bị với thư mục bạn đang dọn dẹp để di chuyển được đổi tên, không phải bản sao!


4
+1 Một lần nữa cho một nhận xét có ý nghĩa với người dùng mới làm quen, điều đó gần như chắc chắn sẽ không dẫn đến việc xóa các tệp vô ý.
kẻ phản diện

4

Sử dụng GLOBIGNORE của bash:

GLOBIGNORE=x.pdf:a.pdf
rm *
unset GLOBIGNORE

Từ trang người đàn ông của bash:

TOÀN CẦU:

            Một danh sách các mẫu được phân tách bằng dấu hai chấm xác định tập hợp
            tên tệp bị bỏ qua bởi mở rộng tên đường dẫn.

Một bài kiểm tra nhanh:

mkdir /tmp/foooooo
cd /tmp/foooooo
touch x.pdf y.zip z.mp3 a.pdf
GLOBIGNORE=x.pdf:a.pdf
ls -1 *

Đầu ra:

y.zip
z.mp3

3

Hãy cẩn thận và sáng tác: sử dụng xargs

Đây là một cách tiếp cận tôi thích, vì nó cho phép tôi rất cẩn thận: soạn một cách để chỉ hiển thị các tệp tôi muốn xóa, sau đó gửi chúng cho rmsử dụng xargs. Ví dụ:

  • ls cho tôi xem tất cả
  • ls | grep pdfcho tôi xem các tập tin tôi muốn giữ Hừm.
  • ls | grep -v pdfcho thấy điều ngược lại: tất cả ngoại trừ những gì tôi muốn giữ. Nói cách khác, nó hiển thị danh sách những thứ tôi muốn xóa. Tôi có thể xác nhận điều này trước khi làm bất cứ điều gì nguy hiểm.
  • ls | grep -v pdf | xargs rmgửi chính xác danh sách đó để rmxóa

Như tôi đã nói, tôi chủ yếu thích điều này vì sự an toàn mà nó mang lại: không có sự tình cờ rm *đối với tôi. Hai lợi thế khác:

  • Đó là composable; bạn có thể sử dụng lshoặc findđể có được danh sách ban đầu, tùy thích. Bạn có thể sử dụng bất cứ thứ gì bạn thích trong quá trình thu hẹp danh sách đó - một cái khác grep, một số awkhoặc bất cứ thứ gì. Nếu bạn chỉ cần xóa các tệp có tên chứa màu, bạn có thể tạo nó theo cách tương tự.
  • Bạn có thể sử dụng mỗi công cụ cho mục đích chính của nó. Tôi thích sử dụng findđể tìm và rmloại bỏ, trái ngược với việc phải nhớ rằng findchấp nhận một -deletelá cờ. Và nếu bạn làm điều này, một lần nữa, bạn có thể soạn các giải pháp thay thế; có thể thay vì rm, bạn có thể tạo một trashlệnh di chuyển tệp vào thùng rác (cho phép "hủy xóa") và chuyển sang đó thay vì rm. Bạn không cần phải có findhỗ trợ tùy chọn đó, bạn chỉ cần chuyển sang tùy chọn đó.

Cập nhật

Xem bình luận của @pabouk để biết cách sửa đổi điều này để xử lý một số trường hợp cạnh, chẳng hạn như ngắt dòng trong tên tệp, tên tệp như my_pdfs.zip, v.v.


4
Tôi nhận thấy ba vấn đề ở đây: a) Nó sẽ loại trừ bất kỳ tập tin pdfnào có chứa bất cứ nơi nào trong tên của nó. --- b) Nó sẽ xóa các tệp PDF nếu bất kỳ chữ cái nào trong hậu tố là chữ hoa. --- c) Không nên sử dụng đầu ra của ls. Nó sẽ không hoạt động với tên tập tin có chứa dòng mới. Một số triển khai lsthay thế các ký tự đặc biệt, ví dụ: tab bằng ?. --- Tốt hơn là sử dụng : find -maxdepth 1 -print0. (không quá ngắn như ls:) ----- Để giải quyết a) và b) sử dụng grep -vi '\.pdf$'giải pháp --- hoàn thành (nhưng chỉ GNU):find -maxdepth 1 -print0 | grep -viz '\.pdf$' | xargs -0 rm
pabouk

1
Tôi hiểu rằng bạn có nghĩa là giải pháp là một quá trình "tương tác" với nhiều lần lặp thủ công nhưng việc kiểm tra sẽ khó có thể sử dụng được cho danh sách dài các tệp và các vấn đề được đề cập ở trên có thể dễ dàng bỏ qua lỗi.
pabouk

1
@pabouk điểm tốt; thế giới thực luôn làm phức tạp mọi thứ và sự điều chỉnh của bạn rất hữu ích. :) Nhưng tôi vẫn nghĩ cách tiếp cận tổng thể này là tốt nhất. Nếu có quá nhiều tệp để xác nhận trực quan mọi thứ, | head -20ít nhất bạn có thể xem liệu nó có trông gần đúng không, trong khi nếu bạn chỉ rm my_pattern, bạn không có cơ hội phát hiện ra một sai lầm lớn.
Nathan Long

1
Bạn có thể tìm thấy cho bạn thấy các tập tin trước khi bạn cũng xóa chúng, bỏ qua -delete và chỉ sử dụng find . -type f ! -name "*.pdf"để in ra bàn điều khiển, hoặc dẫn đến ít hoặc một tập tin. [và sau đó chuyển sang xargs thành rm nếu muốn như nhận xét của pabouk (với -print0 | ... -0 cho tên tệp lạ)]
Xen2050

3

Tôi thường giải quyết các vấn đề như vậy từ trình thông dịch Python tương tác:

mic@mic ~ $ python
>>> import os
>>> for f in os.listdir('.'):
...   if not f.endswith('.pdf'):
...     os.remove(f)

Nó có thể dài hơn một lớp lót với findhoặc xargs, nhưng nó cực kỳ đàn hồi và tôi biết chính xác nó làm gì mà không cần phải nghiên cứu trước.


Đối với những người ngày càng lo lắng với mỗi dòng bổ sung, chúng tôi có thể biến nó thành một:for item in [f for f in os.listdir('.') if not f.endswith('.pdf')]: os.remove(item)
Jacob Vlijm

python -c "import os; for f in os.listdir('.'): if not f.endswith('.pdf'): os.remove(f)"
mic_e

[os.remove(f) for f in os.listdir('.') if not f.endswith('.pdf')]
mic_e

đẹp! cái thứ hai cho tôi một lỗi cú pháp, đừng hiểu tại sao.
Jacob Vlijm

lạ; nó hoạt động với cả python 3.4 và python 2.7 trên hệ thống của tôi.
mic_e

2

câu trả lời tốt hơn (so với câu trả lời trước của tôi) cho câu hỏi này sẽ bằng cách sử dụng filelệnh mạnh mẽ .

$ file -i abc.pdf
abc: application/pdf; charset=binary

bây giờ vấn đề của bạn:

cd <the directory you want to search in>
for var in ./*
do
if file -i "$var" | grep -q 'application/pdf\;'
then
echo "$var"
fi
done

công việc của forlệnh là đưa ra các tệp trong thư mục hiện tại dưới dạng biến $var. if-thenlệnh xuất ra tên của các tệp pdf bằng cách lấy trạng thái thoát 0khỏi file -i "$var" | grep -q 'application/pdf\;'lệnh, nó sẽ chỉ đưa ra trạng thái thoát 0nếu tìm thấy tệp pdf.


1
rm $(ls -lo|grep -v [Pp][Dd][Ff]$|awk '{print $7}')

Cảnh báo! Tốt nhất hãy thử trước

ls -l $(ls -lo|grep -v [Pp][Dd][Ff]$|awk '{print $7}')

2
Ugh, điều này rất thiếu sót trong nhiều cách: smallo.ruhr.de/award.html#ls , smallo.ruhr.de/award.html#grep và nó hoàn toàn bỏ qua tên tệp có khoảng trắng hoặc ký tự đặc biệt.
David Foerster

1
Bạn thực sự nên sử dụng -ivới grepcho phù hợp với case-insensitive.
muru

1
rm -i -- !(*@(a|x).pdf)

Đọc dưới dạng, xóa tất cả các tệp không a.pdfhoặc x.pdf.

Điều này hoạt động bằng cách sử dụng 2 khối lượng mở rộng, bên ngoài !()để phủ định quả cầu chứa trong đó đòi hỏi quả cầu phải khớp với một hoặc nhiều ahoặc xcác mẫu trước .pdfhậu tố. Xem toàn cầu # extglob .

$ ls -a
.dotfile1 .dotfile2 a.pdf x.pdf y.zip z.mp3

$ echo -- !(a.pdf)
-- x.pdf y.zip z.mp3

$ echo -- !(x.pdf)
-- a.pdf y.zip z.mp3

$ echo -- !(a.pdf|x.pdf)
-- y.zip z.mp3

$ echo -- !(@(a|x).pdf)   # NOTE.that this matches the .dotfiles* as well
-- . .. .dotfile1 .dotfile2 y.zip z.mp3

$ echo -- !(*@(a|x).pdf)  # but this doesn't
-- y.zip z.mp3

$ echo rm -i -- !(*@(a|x).pdf)
rm -i -- y.zip z.mp3

1

cách vỏ di động

$ ksh -c 'for i in ./*; do case $i in *.pdf)continue;; *)rm "$i";; esac;done'

Khá nhiều POSIX và tương thích với bất kỳ shell Bourne-style ( ksh, bash, dash). Rất phù hợp cho các tập lệnh di động và khi bạn không thể sử dụng toàn bashcầu shell mở rộng.

perl:

$ perl -le 'opendir(my $d,"."); foreach my $f (grep(-f && !/.pdf/ , readdir($d))){unlink $f};closedir $d'                                                             

Hoặc sạch hơn một chút:

$ perl -le 'opendir(my $d,"."); map{ unlink $_ } grep(-f "./$_" && !/.pdf/ , readdir($d));closedir $d'

trăn thay thế

python -c 'import os;map(lambda x: os.remove(x), filter(lambda x: not x.endswith(".pdf"),os.listdir(".")))'

0

Hãy cẩn thận với những gì bạn đang xóa!

Một cách an toàn để kiểm tra nó trước khi thử xóa là kiểm tra trước ls, vì một số hành vi chưa được kiểm tra có thể xóa các tệp không mong muốn. Và bạn có thể làm điều đó trực tiếp bên ngoài thư mục. lstương tự như rmvậy, vì vậy:

ls sub/path/to/files/!(*.pdf)

Điều này sẽ liệt kê

y.zip
z.mp3

Và bây giờ bạn có thể thấy những gì bạn đang xóa và có thể xóa chúng một cách an toàn:

rm sub/path/to/files/!(*.pdf)

Và đó là nó. Bạn có thể sử dụng ký tự đại diện *để chọn lọc hơn như chỉ giữ các tài liệu khóa học lập trình:

rm sub/path/to/files/!(*programming*)
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.