ลบไฟล์ทั้งหมดยกเว้นไฟล์ที่มีนามสกุลไฟล์ PDF ในไดเรกทอรี


50

ฉันมีไดเรกทอรีที่มีดังต่อไปนี้:

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

ฉันต้องการที่จะลบไฟล์ทั้งหมดนอกเหนือจากและx.pdf a.pdfฉันจะทำสิ่งนี้ได้อย่างไรจากเครื่องเทอร์มินัล ไม่มีไดเรกทอรีย่อยดังนั้นจึงไม่จำเป็นต้องเรียกซ้ำ

คำตอบ:


63
cd <the directory you want>
find . -type f ! -iname "*.pdf" -delete
  • คำสั่งแรกจะนำคุณไปยังไดเรกทอรีที่คุณต้องการลบไฟล์ของคุณ
  • คำสั่งที่สองจะลบไฟล์ทั้งหมดยกเว้นไฟล์ที่ลงท้ายด้วย.pdfชื่อไฟล์

ตัวอย่างเช่นหากมีไดเรกทอรีที่เรียกว่าtempในโฟลเดอร์บ้านของคุณ:

cd ~/temp

จากนั้นลบไฟล์:

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

xyz.pdfนี้จะลบไฟล์ทั้งหมดยกเว้น

คุณสามารถรวมสองคำสั่งนี้กับ:

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

.เป็นไดเรกทอรีปัจจุบัน !หมายถึงการใช้ไฟล์ทั้งหมดยกเว้นไฟล์ที่มี.pdfในตอนท้าย -type fเลือกไฟล์เท่านั้นไม่ใช่ไดเรกทอรี -deleteหมายถึงการลบ

หมายเหตุ: คำสั่งนี้จะลบไฟล์ทั้งหมด (ยกเว้นไฟล์ pdf แต่รวมถึงไฟล์ที่ซ่อนอยู่) ในไดเรกทอรีปัจจุบันและในไดเรกทอรีย่อยทั้งหมด ต้องมาก่อน! -nameก็-nameจะมีเฉพาะ.pdfในขณะที่-inameจะรวมทั้งสอง.pdfและ.PDF

หากต้องการลบเฉพาะในไดเรกทอรีปัจจุบันและไม่อยู่ในไดเรกทอรีย่อยให้เพิ่ม-maxdepth 1:

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

ขอบคุณสำหรับคำตอบ. คุณช่วยฉันเข้าใจไวยากรณ์หน่อยได้ไหม? .หมายถึง "และ"? !หมายถึง "ยกเว้น" -nameหมายความว่าคุณต้องการยกเว้นด้วยพารามิเตอร์ชื่อจากนั้น-deleteจะมีการดำเนินการเมื่อค้นหาหรือไม่ ดังนั้นจึงมองหาทุกอย่างยกเว้น "* .pdf" และลบออกใช่ไหม หรือฉันเข้าใจผิด?
jessenorton

.หมายถึงไดเรกทอรีปัจจุบัน !หมายถึงใช้ไฟล์ทั้งหมดยกเว้นไฟล์ที่มี.pdfในตอนท้าย -deleteหมายถึงการลบ ตอนนี้ฉันชัดเจนไหม
Edward Torvalds

@terdon starkers กล่าวว่าไม่มีย่อย directories.wait ป่วยแก้ไขคำตอบของฉันจะกว้างมากขึ้น
เอ็ดเวิร์ด Torvalds

+1 คุณควรรวม-maxdepth 1พารามิเตอร์ที่จะเริ่มต้นด้วย จากนั้นแนะนำให้ลบพารามิเตอร์ในกรณีที่ต้องการลบแบบเรียกซ้ำ
Tulains Córdova

3
สิ่งนี้ทำให้ฉันทราบว่าเราควรจะใช้-inameแทน-nameหรือไฟล์.PDFที่มีส่วนขยายจะผ่าน
muru

43

ด้วยการbashขยายเชลล์แบบขยายคุณสามารถลบไฟล์ใด ๆ ที่มีส่วนขยายนอกเหนือจากการ.pdfใช้งานได้

rm -- *.!(pdf)

ตามที่ระบุไว้โดย @pts --อักขระจะระบุจุดสิ้นสุดของตัวเลือกคำสั่งใด ๆ ทำให้คำสั่งปลอดภัยในกรณีที่หายากของไฟล์ที่ชื่อขึ้นต้นด้วย-อักขระ

หากคุณต้องการลบไฟล์ที่ไม่มีนามสกุลใด ๆ รวมถึงไฟล์ที่มีนามสกุลอื่นนอกจาก.pdfที่ระบุไว้โดย @DennisWilliams คุณสามารถใช้

rm -- !(*.pdf)

การขยายแบบวงกลมควรเปิดใช้งานโดยค่าเริ่มต้น แต่หากไม่ใช่คุณสามารถทำได้

shopt -s extglob

โดยเฉพาะอย่างยิ่งหากคุณต้องการใช้สิ่งนี้ภายในสคริปต์สิ่งสำคัญที่ควรทราบคือหากนิพจน์ไม่ตรงกับสิ่งใด (เช่นถ้าไม่มีไฟล์ที่ไม่ใช่ไฟล์ pdf ในไดเรกทอรี) จากนั้นค่าเริ่มต้น glob จะถูกส่งไปยังrmคำสั่งทำให้เกิดข้อผิดพลาดเช่น

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

คุณสามารถปรับเปลี่ยนพฤติกรรมเริ่มต้นนี้ได้โดยใช้nullglobตัวเลือกเชลล์อย่างไรก็ตามมีปัญหาของตัวเอง สำหรับการสนทนาที่ละเอียดยิ่งขึ้นดูที่NullGlob - Wiki ของ Greg


IMO วิธีการที่ดีกว่า
Takkat

แล้วไฟล์ที่ไม่มีนามสกุลล่ะ FWIW ใน zsh มันrm *~*.pdf
Emil Jeřábek

1
ฉันจะใส่จุดไว้ในวงเล็บ
Dennis Williamson

4
เครื่องหมายดอกจันก็ควรเข้าไปข้างใน: !(*.py). นอกจากนี้สมมุติว่าถ้า OP ต้องการไฟล์ ".pdf" ที่เหลืออยู่เท่านั้นไฟล์ที่ไม่มีนามสกุลก็ควรจะถูกลบและจะไม่ถูกละเว้นด้วย
Dennis Williamson

1
วิธีนี้ง่ายกว่าและดีกว่าคำตอบที่ยอมรับ
ปีเตอร์

18

ลบไปที่ถังขยะ :

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

หรือผ่านmvคำสั่ง (แต่ด้วยวิธีนี้คุณจะไม่สามารถกู้คืนได้จากถังขยะเนื่องจากไม่ได้บันทึกข้อมูล. trashinfo ดังนั้นหมายความว่าคุณย้ายไฟล์ไปยังปลายทางที่มีดังต่อไปนี้)

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

6
rmวิธีนี้จะมีความปลอดภัยมากกว่าโดยตรงโดยใช้
เซท

14

วิธีที่ง่ายที่สุด: สร้างไดเรกทอรีใหม่ที่ใดที่หนึ่ง (ถ้าคุณเพียงลบในไดเรกทอรีเดียวไม่ซ้ำมันอาจเป็นไดเรกทอรีย่อย); ย้ายไฟล์. pdf ทั้งหมดไปที่นั่น ลบทุกอย่างอื่น ย้ายไฟล์ PDF กลับ ลบไดเรกทอรีกลาง

รวดเร็วง่ายคุณสามารถเห็นสิ่งที่คุณกำลังทำ ตรวจสอบให้แน่ใจว่าไดเรกทอรีระดับกลางอยู่ในอุปกรณ์เดียวกับไดเรกทอรีที่คุณกำลังล้างข้อมูลเพื่อให้การเคลื่อนไหวเปลี่ยนชื่อไม่ใช่คัดลอก!


4
+1 อีกครั้งสำหรับความคิดเห็นที่สมเหตุสมผลสำหรับผู้ใช้มือใหม่ซึ่งแทบจะไม่ส่งผลให้มีการลบไฟล์โดยไม่ได้ตั้งใจ
trognanders

4

ใช้ GLOBIGNORE ของ bash:

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

จากหน้าคนของทุบตี:

GLOBIGNORE:

            รายการรูปแบบที่คั่นด้วยโคลอนจะกำหนดชุด
            ของชื่อไฟล์ที่จะละเว้นโดยการขยายชื่อพา ธ

การทดสอบอย่างรวดเร็ว:

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

เอาท์พุท:

y.zip
z.mp3

3

ระวังและเรียบเรียง: ใช้ xargs

นี่คือวิธีการที่ผมชอบเพราะมันช่วยให้ฉันต้องระวังให้มาก: เขียนวิธีที่จะแสดงเพียงไฟล์ที่ฉันต้องการจะลบแล้วส่งพวกเขาไปใช้rm xargsตัวอย่างเช่น:

  • ls แสดงให้ฉันเห็นทุกอย่าง
  • ls | grep pdfแสดงไฟล์ที่ฉันต้องการเก็บไว้ อืมมม
  • ls | grep -v pdfแสดงสิ่งที่ตรงกันข้าม: ทั้งหมดยกเว้นสิ่งที่ฉันต้องการเก็บไว้ พูดอีกอย่างคือมันแสดงรายการสิ่งที่ฉันต้องการลบ ฉันสามารถยืนยันสิ่งนี้ก่อนที่จะทำอะไรอันตราย
  • ls | grep -v pdf | xargs rmส่งรายการนั้นไปยังrmการลบอย่างแน่นอน

อย่างที่ฉันพูดฉันชอบเรื่องนี้เป็นหลักเพื่อความปลอดภัย: ไม่มีอุบัติเหตุrm *สำหรับฉัน ข้อดีสองประการอื่น ๆ :

  • มันแต่งได้ คุณสามารถใช้lsหรือfindเพื่อรับรายการเริ่มต้นตามที่คุณต้องการ คุณสามารถใช้สิ่งอื่นที่คุณชอบในกระบวนการ จำกัด รายการนั้น - grepบางรายการawkหรืออะไรก็ตาม หากคุณต้องการลบเฉพาะไฟล์ที่ชื่อมีสีคุณสามารถสร้างมันขึ้นมาได้ด้วยวิธีเดียวกัน
  • คุณสามารถใช้เครื่องมือแต่ละอย่างเพื่อจุดประสงค์หลัก ฉันชอบที่จะใช้findในการค้นหาและrmลบออกซึ่งต่างจากการจำได้ว่าfindยอมรับการ-deleteตั้งค่าสถานะ และถ้าคุณทำเช่นนี้อีกครั้งคุณสามารถเขียนทางเลือก อาจจะแทนrmคุณสามารถสร้างtrashคำสั่งที่จะย้ายไฟล์ไปที่ถังขยะ (ให้ "ยกเลิกการลบ") rmและท่อที่แทน คุณไม่จำเป็นต้องได้findรับการสนับสนุนตัวเลือกนั้นคุณเพียงไปที่มัน

ปรับปรุง

ดูความคิดเห็นโดย @pabouk สำหรับวิธีแก้ไขสิ่งนี้เพื่อจัดการกับกรณีขอบบางอย่างเช่นตัวแบ่งบรรทัดในชื่อไฟล์ชื่อไฟล์เช่นmy_pdfs.zipฯลฯ


4
ฉันสังเกตเห็นปัญหาสามข้อที่นี่: ก)มันจะยกเว้นไฟล์ที่มีpdfชื่อใด ๆ --- b)มันจะลบไฟล์ PDF หากตัวอักษรใด ๆ ในคำต่อท้ายเป็นตัวพิมพ์ใหญ่ --- c)lsมันไม่ได้เป็นความคิดที่ดีที่จะใช้การส่งออกของ มันจะไม่ทำงานกับชื่อไฟล์ที่มีการขึ้นบรรทัดใหม่ การใช้งานบางส่วนของแทนที่ตัวอักษรพิเศษเช่นโดยแท็บls ?--- find -maxdepth 1 -print0มันจะดีกว่าที่จะใช้: (ไม่สั้นอย่างที่ls:) ----- เพื่อแก้ปัญหา a) และ b) ใช้grep -vi '\.pdf$'--- โซลูชันที่สมบูรณ์ (แต่ GNU เท่านั้น):find -maxdepth 1 -print0 | grep -viz '\.pdf$' | xargs -0 rm
pabouk

1
ฉันเข้าใจว่าคุณหมายถึงวิธีแก้ปัญหาเป็นกระบวนการ "เชิงโต้ตอบ" ที่มีการทำซ้ำหลายรายการด้วยตนเอง แต่การตรวจสอบจะใช้งานได้ยากสำหรับรายการไฟล์ที่ยาวและปัญหาดังกล่าวข้างต้นอาจทำให้มองข้ามข้อผิดพลาดได้ง่าย
pabouk

1
@pabouk จุดดี; โลกแห่งความจริงมักทำให้สิ่งต่าง ๆ ซับซ้อนและการแก้ไขของคุณก็มีประโยชน์ :) แต่ฉันก็ยังคิดว่าวิธีการโดยรวมนี้ดีที่สุด หากมีไฟล์จำนวนมากเกินไปที่จะยืนยันทุกอย่างด้วยสายตาคุณ| head -20อย่างน้อยสามารถดูได้ว่ามันดูถูกต้องหรือไม่ในขณะที่ถ้าคุณเพิ่งrm my_patternคุณจะไม่มีโอกาสพบข้อผิดพลาดครั้งใหญ่
Nathan Long

1
คุณสามารถค้นหาให้แสดงไฟล์ก่อนที่จะลบออกไปทิ้ง -delete และใช้find . -type f ! -name "*.pdf"เพื่อพิมพ์ไปยังคอนโซลหรือไปป์ที่น้อยกว่าหรือไฟล์ [จากนั้นไปป์ที่ xargs ถึง rm หากต้องการเช่นความคิดเห็นของ pabouk (ด้วย -print0 | ... -0 สำหรับชื่อไฟล์แปลก)]
Xen2050

3

ฉันมักจะแก้ปัญหาดังกล่าวจากล่าม Python แบบโต้ตอบ:

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

มันอาจจะยาวกว่าหนึ่งซับด้วยfindหรือxargsแต่ก็ยืดหยุ่นอย่างมากและฉันรู้ว่ามันทำอะไรโดยไม่ต้องค้นคว้าก่อน


สำหรับผู้ที่มีความกังวลมากขึ้นกับทุกบรรทัดเพิ่มเติมเราสามารถทำให้มันเป็นหนึ่ง: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

ดี! ข้อที่สองให้ฉันข้อผิดพลาดทางไวยากรณ์ไม่เห็นว่าทำไม
Jacob Vlijm

แปลก; มันทำงานได้กับทั้ง python 3.4 และ python 2.7 บนระบบของฉัน
mic_e

2

คำตอบที่ดีกว่า (เทียบกับคำตอบก่อนหน้าของฉัน) กับคำถามนี้จะใช้fileคำสั่งที่มีประสิทธิภาพ

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

ตอนนี้ปัญหาของคุณ:

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

การปฏิบัติงานของคำสั่งให้ไฟล์ในไดเรกทอรีปัจจุบันในรูปแบบของตัวแปรfor คำสั่งแสดงชื่อของไฟล์ PDF โดยการออกจากสถานะของจากคำสั่งก็จะให้ออกจากสถานะของเท่านั้นหากพบไฟล์ PDF$varif-then0file -i "$var" | grep -q 'application/pdf\;'0


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

คำเตือน! ดีกว่าลองก่อน

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

2
อืมสิ่งนี้มีข้อบกพร่องในหลาย ๆ ด้าน: smallo.ruhr.de/award.html#ls , smallo.ruhr.de/award.html#grepและมันจะไม่สนใจชื่อไฟล์ที่มีช่องว่างหรืออักขระพิเศษทั้งหมด
David Foerster

1
คุณควรใช้-iกับgrepการจับคู่แบบตรงตามตัวพิมพ์ใหญ่ - เล็ก
muru

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

อ่านเป็นลบไฟล์ทั้งหมดที่ไม่ได้หรือa.pdfx.pdf

นี้ทำงานโดยการใช้ 2 globs ขยายด้านนอก!()เพื่อแก้ glob อยู่ที่ตัวเองต้องการให้ glob จะต้องตรงกับหนึ่งหรือมากกว่าaหรือxรูปแบบก่อนที่จะ.pdfต่อท้าย ดูglob # 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

เปลือกแบบพกพา

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

พริตตี้ POSIX มากและเข้ากันได้กับบอร์นเชลล์สไตล์ ( ksh, bash, dash) เหมาะอย่างยิ่งสำหรับสคริปต์แบบพกพาและเมื่อคุณไม่สามารถใช้bashเชลล์แบบขยายได้

Perl:

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

หรือทำความสะอาดเล็กน้อย:

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

หลามทางเลือก

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

0

ระวังสิ่งที่คุณกำลังลบอยู่!

วิธีที่ปลอดภัยในการทดสอบก่อนที่จะพยายามลบคือการทดสอบก่อนด้วยlsเนื่องจากพฤติกรรมที่ไม่ถูกตรวจจับบางอย่างสามารถลบไฟล์ที่ไม่ต้องการได้ และคุณสามารถทำได้โดยตรงนอกไดเรกทอรี lsคล้ายกับrmดังนั้น:

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

รายการนี้จะ

y.zip
z.mp3

และตอนนี้คุณสามารถเห็นสิ่งที่คุณกำลังลบและสามารถลบได้อย่างปลอดภัย:

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

และนั่นคือมัน Yo สามารถใช้สัญลักษณ์แทน*เพื่อเลือกเพิ่มเติมเช่นการเก็บเอกสารหลักสูตรการเขียนโปรแกรมเท่านั้น:

rm sub/path/to/files/!(*programming*)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.