ลบไฟล์ แต่ไม่รวมไฟล์ทั้งหมดในรายการ


17

ฉันจำเป็นต้องล้างโฟลเดอร์เป็นระยะ ฉันได้รับ filelist ที่มีข้อความอนุญาตให้ใช้ไฟล์ใดได้บ้าง ตอนนี้ฉันต้องลบไฟล์ทั้งหมดที่ไม่ได้อยู่ในไฟล์นี้

ตัวอย่าง:

dont-delete.txt:

dontdeletethisfile.txt
reallyimportantfile.txt
neverdeletethis.txt
important.txt

โฟลเดอร์ของฉันทำความสะอาดประกอบด้วยสิ่งนี้:

ls /home/me/myfolder2tocleanup/:

dontdeletethisfile.txt
reallyimportantfile.txt
neverdeletethis.txt
important.txt
this-can-be-deleted.txt
also-waste.txt
never-used-it.txt

ดังนั้นควรลบไฟล์นี้:

this-can-be-deleted.txt
also-waste.txt
never-used-it.txt

ฉันค้นหาบางอย่างเพื่อสร้างคำสั่งลบพร้อมตัวเลือกเพื่อแยกไฟล์บางไฟล์ที่มีให้


นี่เป็นการบ้านหรือไม่?
mook765

ฉันหวังว่าคุณจะไม่ใช่ครูของเขา lol
Gujarat Santana

2
@gujarat เราไม่ได้ให้บริการทำการบ้านฟรี สำหรับคำถามตัวเองมันอาจจะเป็นประโยชน์กับคนอื่น ๆ ดังนั้นจึงเปิดจนถึง
Sergiy Kolodyazhnyy

@Serg ฉันเห็นด้วยกับคุณโดยสิ้นเชิง
Gujarat Santana

คำตอบ:


9

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

check directoryส่วนจะช่วยให้คุณไม่ได้ตั้งใจเรียกใช้สคริปต์จากไดเรกทอรีที่ไม่ถูกต้องและบังคับไฟล์ผิด

คุณสามารถลบecho deletingบรรทัดเพื่อให้ทำงานอย่างเงียบ ๆ

#!/bin/bash

cd /home/me/myfolder2tocleanup/

# Exit if the directory isn't found.
if (($?>0)); then
    echo "Can't find work dir... exiting"
    exit
fi

for i in *; do
    if ! grep -qxFe "$i" filelist.txt; then
        echo "Deleting: $i"
        # the next line is commented out.  Test it.  Then uncomment to removed the files
        # rm "$i"
    fi
done

ฉันแก้ไขโค้ดของคุณเพื่อหลีกเลี่ยงการใช้งานที่ไร้ประโยชน์lsและการจับเอาท์พุทที่ไร้ประโยชน์grepหากสิ่งที่คุณต้องการทราบคือการแข่งขันหรือไม่ ฉันยังใช้รูปแบบสตริงคงที่เพื่อหลีกเลี่ยงปัญหาการหลบหนี
David Foerster

@DavidFoerster ขอบคุณสำหรับการสนับสนุน อย่างไรก็ตามเมื่อคุณเปลี่ยนwhileลูปเป็นforลูปคุณจะเปลี่ยนiteration keyจากiเป็นfเป็น ในการประกาศซึ่งทำลายรหัส ฉันซ่อมมัน.
LD James

โอ๊ะพลังแห่งนิสัย fฉันมักจะย่อชื่อตัวแปรเปลือกสำหรับชื่อไฟล์เป็น ;-P (…และ +1 สำหรับคำตอบของคุณซึ่งฉันลืมไปก่อนหน้านี้)
David Foerster

10

สคริปต์ python นี้สามารถทำได้:

#!/usr/bin/env python3
import os
no_remove = set()
with open('./dont-delete.txt') as f:
     for line in f:
         no_remove.add(line.strip())

for f in os.listdir('.'):
    if f not in no_remove:
        print('unlink:' + f ) 
        #os.unlink(f)

ส่วนที่สำคัญคือการไม่แสดงความคิดเห็น os.unlink()ฟังก์ชั่น

หมายเหตุ : เพิ่มสคริปต์นี้และdont-delete.txtของคุณdont-delete.txtเพื่อให้พวกเขาทั้งสองอยู่ในรายการและเก็บไว้ในไดเรกทอรีเดียวกัน


1
ฉันเปลี่ยนรหัสของคุณเพื่อใช้setแทนรายการสำหรับ O (1) แทนการค้นหา O (n) ในส่วนที่สอง
David Foerster

ขอบคุณสำหรับความช่วยเหลือของคุณฉันปกติหน้าต่างเป็นผู้ชาย แต่ตะเข็บหลามเกินไปจะเย็น =)
stefan83

1
@ stefan83: Python ทำงานได้ดีบน Windows
David Foerster

3

นี่คือหนึ่งซับ:

comm -2 -3 <(ls) <(sort dont_delete) | tail +2 | xargs -p rm
  1. ls พิมพ์ไฟล์ทั้งหมดในไดเรกทอรีปัจจุบัน (เรียงตามลำดับ)
  2. sort dont_delete พิมพ์ไฟล์ทั้งหมดที่เราไม่ต้องการลบตามลำดับ
  3. <()ผู้ประกอบการหันสตริงเป็นวัตถุไฟล์เหมือน
  4. commคำสั่งเปรียบเทียบสองไฟล์ก่อนเรียงและพิมพ์ออกเส้นที่พวกเขาแตกต่าง
  5. การใช้-2 -3ค่าสถานะทำให้เกิดcommการพิมพ์เฉพาะบรรทัดที่มีอยู่ในไฟล์แรก แต่ไม่ใช่ที่สองซึ่งจะเป็นรายการไฟล์ที่ปลอดภัยที่จะลบ
  6. การtail +2เรียกใช้เพียงเพื่อลบส่วนหัวของcommเอาต์พุตซึ่งมีชื่อของไฟล์อินพุต
  7. ตอนนี้เราได้รับรายชื่อไฟล์ที่จะลบตามมาตรฐาน เราท่อส่งออกนี้เพื่อที่จะเปลี่ยนกระแสออกในรายการของอาร์กิวเมนต์สำหรับxargs กองกำลังตัวเลือกที่จะขอยืนยันก่อนที่จะดำเนินการrm-pxargs

ขอบคุณสำหรับความช่วยเหลือของคุณตอนนี้ฉันมีทางออกของฉัน!
stefan83

@gardenhead ฉันเหนื่อยกับรหัสของคุณ แต่จะลบไฟล์ทั้งหมดในไดเรกทอรีและเก็บเฉพาะไฟล์แรกและไฟล์สุดท้ายในรายการ dont-delete คุณมีความคิดใด ๆ สำหรับปัญหานี้หรือไม่? ขอบคุณล่วงหน้า.
Negar

1

FWIW ดูเหมือนว่าคุณสามารถทำสิ่งนี้ได้zshโดยใช้โปรแกรม(+cmd)คัดเลือกรอบตัว

เพื่ออธิบายให้เริ่มกันด้วยไฟล์บางไฟล์

 % ls
bar  baz  bazfoo  keepfiles.txt  foo  kazoo

และไฟล์รายการที่อนุญาต

 % cat keepfiles.txt
foo
kazoo
bar

ก่อนอื่นให้อ่านรายการที่อนุญาตในอาร์เรย์:

 % keepfiles=( "${(f)$(< keepfiles.txt)}" )

หรืออาจจะดีกว่า

 % zmodload zsh/mapfile
 % keepfiles=( ${(f)mapfile[./keepfiles.txt]} )

(เทียบเท่ากับmapfilebuiltin ของ bash - หรือคำพ้องความหมายreadarray) ตอนนี้เราสามารถตรวจสอบว่ามีคีย์ (ชื่อไฟล์) อยู่ในอาร์เรย์โดยใช้${keepfiles[(I)filename]}ซึ่งส่งกลับค่า 0 หากไม่พบรายการที่ตรงกัน:

 % print ${keepfiles[(I)foo]}
1
 % print ${keepfiles[(I)baz]}
0
 %

เราสามารถใช้ฟังก์ชั่นนี้เพื่อสร้างฟังก์ชั่นที่ส่งคืนtrueหากไม่มีการจับคู่$REPLYในอาร์เรย์:

% nokeep() { (( ${keepfiles[(I)$REPLY]} == 0 )); }

สุดท้ายเราใช้ฟังก์ชันนี้เป็นตัวระบุในคำสั่งของเรา:

 % ls *(+nokeep)
baz  bazfoo  keepfiles.txt

หรือในกรณีของคุณ

 % rm -- *(+nokeep)

(คุณอาจต้องการเพิ่มชื่อของไฟล์ที่อนุญาตให้ตัวเองลงในรายการที่อนุญาต)


0

สมมติว่า bash shell ของคุณมีการextglob shoptตั้งค่าไว้ที่นี่เป็นทางเลือกที่ค่อนข้างอนุรักษ์นิยม:

rm !($(tr \\n \| < keep.txt))

(... พร้อมกับคำแนะนำการสื่อสารที่ยอดเยี่ยมของ @ gardenhead!)


0

เว้นแต่ว่าการส่งออกของls /home/me/myfolder2tocleanup/เกินกว่าข้อ จำกัด เปลือกสูงสุด ARG_MAXที่ประมาณ2MBสำหรับ Ubuntu ฉันจะแนะนำต่อไปนี้


การประยุกต์ใช้คำสั่งหนึ่งบรรทัดที่จะทำงานจะเป็นดังนี้:

  1. คัดลอกdont-delete.txtไฟล์ไปยังไดเรกทอรีที่มีไฟล์ที่จะลบดังนี้:
cp dont-delete.txt /home/me/myfolder2tocleanup/
  1. cd ไปยังไดเรกทอรีที่มีไฟล์ที่จะลบเช่น:
cd /home/me/myfolder2tocleanup/
  1. ดำเนินการแบบ dry-run เพื่อทดสอบคำสั่งและทำให้มันพิมพ์ชื่อของไฟล์ที่ตรวจพบว่าถูกลบโดยไม่ต้องลบออกจริง ๆ เช่น:
ls -p | grep -v / | sed 's/\<dont-delete.txt\>//g' | sort | comm -3 - <(sort dont-delete.txt) | xargs echo | tr " " "\n"
  1. หากคุณพอใจกับเอาต์พุตให้ลบไฟล์โดยรันคำสั่งดังนี้:
ls -p | grep -v / | sed 's/\<dont-delete.txt\>//g' | sort | comm -3 - <(sort dont-delete.txt) | xargs rm

ชี้แจง:

  • ls -pจะแสดงรายการไฟล์และไดเรกทอรีทั้งหมดในไดเรกทอรีปัจจุบันและตัวเลือก-pจะเพิ่ม/ชื่อไดเรกทอรี
  • grep -v /จะยกเว้นไดเรกทอรีโดยลบรายการทั้งหมดที่มี a /ในชื่อ
  • sed 's/\<dont-delete.txt\>//g'จะยกเว้นdont-delete.txtไฟล์ดังนั้นจะไม่ถูกลบในกระบวนการ
  • sortlsจะเพียงเพื่อให้แน่ใจว่าการเรียงลำดับการส่งออกที่ยังเหลืออยู่ของ
  • comm -3 - <(sort dont-delete.txt)จะเรียงลำดับdont-delete.txtไฟล์เปรียบเทียบกับเอาต์พุตที่เรียงลำดับlsแล้วและแยกชื่อไฟล์ที่มีอยู่ในทั้งสอง
  • xargs rmlsจะลบทั้งหมดชื่อไฟล์ที่เหลืออยู่ในการส่งออกของการประมวลผลแล้ว ซึ่งหมายความว่าทุกรายการในไดเรกทอรีปัจจุบันจะถูกลบออกยกเว้นไดเรกทอรี , ไฟล์ที่ระบุไว้ในdont-delete.txtไฟล์และไฟล์ตัวเองdont-delete.txt

ในส่วนที่แห้ง:

  • xargs echo จะพิมพ์ไฟล์ที่ควรลบ
  • tr " " "\n" จะแปลช่องว่างเป็นบรรทัดใหม่เพื่อให้อ่านง่ายขึ้น

0

ฉันขอแนะนำอย่างยิ่งให้ใช้rsyncวิธีแก้ไขปัญหาโพสต์ที่นี่ ; อื่นใช้วิธีการแก้ปัญหาด้านล่างโดยมีเงื่อนไขพิเศษที่กล่าวถึง

สมมติว่าไม่มีช่องว่าง (ช่องว่าง / แท็บ) ในไฟล์ของคุณที่ระบุไว้ในไฟล์ที่เรียกว่าexcludelistจากนั้นคุณจะทำ:

find /path/to -type f \( ! -name "excludelist" $(printf ' -a ! -name %s\n' $(< excludelist)) \)

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

find /path/to -type f \( ! -name "excludelist" $(printf ' -a ! -name %s\n' $(< excludelist)) \) -exec echo rm {} \;

หรือใช้-execร่วมกับ+ terminatorแทน

find /path/to -type f \( ! -name "excludelist" $(printf ' -a ! -name %s\n' $(< excludelist)) \) -exec echo rm {} +

echo จะใช้ในการแห้ง


-1

คำแนะนำของฉันคือ:

sed -e 's/^/\.\//' dont-delete.txt > dont-delete-relative-path.txt
find . -type f -print | grep -Fxvf dont-delete-relative-path.txt | xargs -d'\n' rm

อัปเดต 2018-08-07

ตัวอย่าง:

1: mkdir /tmp/delete-example && cd /tmp/delete-example
2: touch a b c d
3: echo "./a\n./b\n./dont-delete.txt\n" > dont-delete.txt
4: find . -type f -print | grep -Fxvf dont-delete.txt | xargs -d'\n' rm

หมายเหตุหลังจากบรรทัดที่ 3 คุณจะมีdont-delete.txtไฟล์พร้อมเนื้อหา:

./a
./b
./dont-delete.txt

(ผู้นำ./เป็นสิ่งสำคัญมาก )

ไฟล์cและdจะถูกลบ


ฉันลองสิ่งนี้ด้วยไฟล์ข้อความของชื่อไฟล์คั่นด้วยบรรทัดใหม่ มันสิ้นสุดการลบไฟล์ทั้งหมดในไดเรกทอรี
Jacques MALAPRADE

ฉันเดาว่า "รายการที่เก็บไว้" ของคุณผิด
nyxz

ฉันได้เพิ่มตัวอย่างการใช้งาน
nyxz
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.