ลบไฟล์ทั้งหมดในไดเรกทอรีที่มีชื่อไม่ตรงกับบรรทัดในรายการไฟล์


9

ฉันมีไดเรกทอรีที่มีไฟล์มากกว่า 1,000 ไฟล์ ในไฟล์ข้อความฉันมีประมาณ 50 ชื่อไฟล์หนึ่งรายการต่อบรรทัด ฉันต้องการลบไฟล์ทั้งหมดในไดเรกทอรีที่ชื่อไฟล์ไม่สอดคล้องกับรายการในรายการ วิธีที่ดีที่สุดในการทำเช่นนี้คืออะไร? ฉันเริ่มเชลล์สคริปต์ แต่ไม่สามารถระบุคำสั่งที่เหมาะสมเพื่อกำหนดในชื่อไฟล์ที่อยู่ในรายการ ขอบคุณ

คำตอบ:


8

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

ควรใช้กับไฟล์ที่ไม่มีที่ว่างในชื่อ:

ขั้นแรกสร้างชื่อไฟล์ของคุณใหม่เพื่อให้แน่ใจว่าตรงกับชื่อไฟล์ที่ถูกต้อง:

sed -e 's,^,^,' -e 's,$,$,'  filelist  > newfilelist 

สร้างคำสั่ง rm

cd your_directory
ls | egrep -vf newfilelist   | xargs -n 1 echo rm  >  rmscript

ตรวจสอบว่าสคริปต์ rm เหมาะสมกับคุณหรือไม่ (คุณสามารถทำได้ด้วย "vim" หรือ "less")
จากนั้นดำเนินการ:

sh -x rmscript

หากไฟล์มีช่องว่างในชื่อ (หากไฟล์นั้นมี"ชื่ออยู่สิ่งนี้จะไม่ทำงาน):

ls | egrep -vf newfilelist  | sed 's,^\(.*\)$,rm "\1",' > rmscript

แน่นอนว่า filelist ไม่ควรอยู่ในไดเรกทอรีเดียวกัน!

แก้ไขแล้ว:

รายการไฟล์ของนาธานมีชื่อที่ตรงกับไฟล์ทั้งหมดในไดเรกทอรี (เช่น "html" ตรงกับ "bob.html") ดังนั้นจึงไม่มีอะไรถูกลบเพราะegrep -vfดูดซับกระแสทั้งหมด ฉันเพิ่มคำสั่งเพื่อใส่ "^" และ "$" รอบชื่อไฟล์แต่ละชื่อ ฉันโชคดีที่รายชื่อไฟล์ของนาธานนั้นถูกต้อง จะมีการจัดรูปแบบ DOS ด้วยเส้นสิ้นสุด CR-LF หรือมีช่องว่างเพิ่มเติมไม่มีไฟล์ที่จะถูกเก็บรักษาไว้โดย egrep และถูกลบทั้งหมด


เมื่อฉันรันคำสั่งแสดงตัวอย่างฉันได้หนึ่งบรรทัดด้วย "rm" เมื่อฉันรันคำสั่งจริงฉันได้รับข้อความแสดงข้อผิดพลาดเกี่ยวกับอาร์กิวเมนต์ที่หายไปสำหรับ rm ฉันต้องใช้ไวยากรณ์พิเศษเพื่อใช้ผลลัพธ์จาก ls | หรือไม่ egrep ในอินพุต xargs?
นาธาน

@Nathan คุณต้อง cd ไปยังไดเรกทอรีของคุณก่อน ไม่มีไวยากรณ์พิเศษ lsระบุชื่อไฟล์ไดเรกทอรีegrep -vf filelistกรองชื่อไฟล์ 50 ชื่อของคุณ ฉันเกรงว่าคุณจะลบไฟล์ทั้งหมดของคุณ
Emmanuel

@Emamanuel ฉันใช้คำสั่งจากไดเรกทอรีที่มีไฟล์ที่จะลบ
นาธาน

@Nathan ไฟล์ทั้งหมดของคุณถูกลบหรือไม่
Emmanuel

ไม่พวกเขายังคงอยู่ที่นั่น
นาธาน

1

สร้างอาร์กิวเมนต์ล่วงหน้าให้กับfind:

{
  read -r
  keep=( -name "$REPLY" ) # no `-o` before the first one.
  while read -r; do
    keep+=( -o -name "$REPLY" )
  done
} < file_list.txt
find . -type f ! \( "${keep[@]}" \) -exec echo rm {} +

ใช้echoชิ้นส่วนเพื่อดูว่าจะสร้างอะไร นำechoชิ้นส่วนออกเพื่อใช้งานจริง

อัปเดต: การสาธิต:

##
# Demonstrate what files exist for testing.
# Show their whitespace:
~/foo $ printf '"%s"\n' *
" op"
" qr"
"abc"
"def"
"gh "
"ij "
"k l"
"keep"
"m n"

##
# Show the contents of the "keep" file,
# Including its whitespace:
~/foo $ cat -e keep
keep$
abc$
gh $
k l$
 op$

##
# Execute the script:
~/foo $ { read -r; keep=( -name "$REPLY" ); while read -r ; do keep+=( -o -name "$REPLY" ); done } < keep
~/foo $ find . -type f ! \( "${keep[@]}" \) -exec rm {} +

##
# Show what files remain:
~/foo $ printf '"%s"\n' *
" op"
"abc"
"gh "
"k l"
"keep"

ฉันชอบอันนี้ดีที่สุดเพราะมันช่วยขจัดความจำเป็นสำหรับนักสร้างหนังก่อน
eyoung100

+1 จากฉันแม้ว่ามันจะไม่จัดการกับช่องว่างได้เป็นอย่างดี บางทีบางคำพูดเดียว ( ') ควรจะเพิ่มคือและkeep=( -name \'"$REPLY"\' ) keep+=( -o -name \'"$REPLY"\' )
Cristian Ciupitu

ด้านบนเป็นอันตรายเนื่องจากคุณสามารถลบไฟล์โดยไม่ตั้งใจได้
davidva

@CristianCiupitu ไม่ได้เหรอ? ฉันได้เพิ่มตัวอย่างที่แสดงว่ามันจัดการกับช่องว่างได้เป็นอย่างดี
kojiro

@davidva ภายใต้สถานการณ์อะไร เมื่อใดก็ตามที่คุณลบสิ่งที่คุณเสี่ยงต่อการทำผิดพลาดโดยอัตโนมัติ แต่ภายในพารามิเตอร์ของคำถามที่ฉันคิดว่าการสาธิตของฉันพิสูจน์ให้เห็นว่าวิธีการนี้เป็นเสียงที่ดี
kojiro

1

ด้วยzsh:

mylist=(${(f)"$(<filelist)"})
print -rl -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

มันอ่านบรรทัดของfilelistอาเรย์แล้วใช้glob qualifiers / estringเพื่อ glob / select เฉพาะชื่อไฟล์ที่ไม่ได้อยู่ในอาเรย์: .เลือกไฟล์ปกติเท่านั้น (เพิ่มDถ้ารายการของคุณมี dotfiles) และ negated ^e_'expression'_เพิ่มเติมเลือกเฉพาะสำหรับ ซึ่งเท็จผลตอบแทนการแสดงออกเช่นถ้าชื่อของพวกเขา ( $REPLY) ไม่ได้เป็นองค์ประกอบของอาร์เรย์
หากคุณพอใจกับผลลัพธ์ให้แทนที่print -rlด้วยrmเพื่อลบไฟล์จริง:

rm -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

ในการเลือกและลบไฟล์ซ้ำ ๆ ให้ใช้*/**glob with ${REPLY:t}glob modifier:

rm -- */**(.^e_'(($mylist[(Ie)${REPLY:t}]))'_)

0

หากคุณใส่เนื้อหาของไดเรกทอรีลงในไฟล์ดังนี้:

cd <somedirectory>
ls >> filelist

เปิด Filelist ด้วยโปรแกรมแก้ไขข้อความและลบไฟล์ทั้งหมดยกเว้นคนที่คุณต้องการลบ นั่นเป็นตัวหนาเพราะเป็นวิธีที่ตรงกันข้ามกับคำตอบข้างต้น

ลองสิ่งนี้:

while read p || [[ -n $p ]]; 
echo $p
done < filelist

หากคุณเห็นรายการไฟล์ที่ส่งออกไปยังหน้าจอแทนที่เสียงก้องด้วยrm -vเช่น:

while read p || [[ -n $p ]]; 
rm -v $p
done < filelist

0

เรียกใช้สคริปต์ด้านล่าง

  1. all_filesตอนแรกผมกำลังหาไฟล์ทั้งหมดที่มีอยู่ภายในไดเรกทอรีและการจัดเก็บการส่งออกไปยังแฟ้มอื่น
  2. เรามีไฟล์ที่มีรายการไฟล์ที่ไม่ควรลบ ( not_to_be_deleted_files)
  3. ฉันกำลังเพิ่มชื่อไฟล์not_to_be_deleted_filesและ files_to_be_deletedท้ายที่สุดnot_to_be_deleted_filesเพราะเราต้องการ 2 ไฟล์เหล่านี้
  4. ตอนนี้ฉันกำลังค้นหาไฟล์ที่ต้องลบโดยใช้joinคำสั่งlinux และเปลี่ยนเส้นทางผลลัพธ์ไปยังfiles_to_be_deleted ไฟล์
  5. ตอนนี้ในที่สุดในขณะที่วงฉันอ่านชื่อไฟล์ทั้งหมดใน files_to_be_deletedและลบไฟล์ที่กล่าวถึงในชื่อไฟล์นั้น

สคริปต์ดังต่อไปนี้

find /home/username/directory -type f | sed 's/.*\///' > all_files
echo all_files >> not_to_be_deleted_files
echo not_to_be_deleted_files >> not_to_be_deleted_files
echo files_to_be_deleted >> not_to_be_deleted_files
join -v 1 <(sort all_files_listed) <(sort files_not_to_be_deleted) >   files_to_be_deleted
while read file
rm  "$file"
done < files_to_be_deleted

PS : echo scriptname >> not_to_be_deleted_filesน่าจะเป็นถ้าคุณต้องการนี้จะถูกบันทึกไว้เป็นสคริปต์และเรียกใช้มันคุณสามารถเพิ่มชื่อสคริปต์ที่ยังมีการใช้

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


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

0

ฉันไปเพื่อวิธีที่ปลอดภัยกว่าและเร็วกว่ามากเพราะฉันมีไฟล์ 18,000 ไฟล์ในรายการ! ฉันต้องล้างรูปภาพในการติดตั้ง Drupal ขนาดใหญ่

การลบไฟล์ทั้งหมดที่ไม่อยู่ในรายการจะเหมือนกับการเก็บเฉพาะไฟล์ที่อยู่ในรายการ ดังนั้นฉันจึงตัดสินใจที่จะคัดลอกไฟล์จากรายการไปยังตำแหน่งอื่น แต่การคัดลอกไฟล์ 20 GB จะใช้พื้นที่มากเกินไปและช้ามากเช่นกัน ดังนั้นเคล็ดลับคือการคัดลอกไฟล์เป็นhardlinksแทนโดยใช้ตัวเลือกในการ-l cpใช้พื้นที่เกือบจะไม่มีและรวดเร็วมาก นอกจากนี้เนื่องจากฉันต้องการรักษาโครงสร้างไดเรกทอรีฉันจึงใช้--parentsตัวเลือก

นี่คือข้อความที่ตัดตอนมาจากรายการไฟล์ของฉัน:

1px.png
misc/feed.png
modules/file/icons/x-office-presentation.png
modules/file/icons/x-office-spreadsheet.png
newsletter.png
sites/all/libraries/ckeditor/plugins/smiley/images/devil_smile.png
sites/all/libraries/ckeditor/plugins/smiley/images/regular_smile.png
sites/default/files/009313_PwC_banner_CBS_Observer_180x246px.jpg

ดังนั้นตัวอย่างจะเป็นโดยที่ temp เป็นปลายทาง:

cp -l --parents 'misc/feed.png' temp

สิ่งนี้จะสร้างโครงสร้างนี้:

temp
  misc
    feed.png

โปรดทราบว่า destinaton จะต้องอยู่ในระบบไฟล์เดียวกันกับแหล่งข้อมูลเพื่อให้ฮาร์ดลิงก์ทำงานได้

ขั้นตอนต่อไปคือการสร้างสคริปต์:

sed -e "s,^,cp -l --parents '," -e "s,$,' /some/where/temp," filelist > newfilelist

ทีนี้สมมุติว่าคุณสร้าง dir ที่ว่างเปล่า / บาง / ที่ไหน / temp แล้วคุณสามารถคัดลอกไฟล์แบบนี้:

sh newfilelist 2> missing_files

missing_filesหมายเหตุว่าข้อผิดพลาดจบลงใน โบนัสเพิ่มเติมของวิธีนี้คือคุณจะได้รับรายชื่อไฟล์จากรายการดั้งเดิมที่ไม่มีอยู่จริง!

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

ในที่สุดย้ายไฟล์และโฟลเดอร์จาก temp กลับไปที่ตำแหน่งเดิม

สำหรับไฟล์ 18,000 ไฟล์ใช้เวลาเพียงไม่กี่วินาที


0

ปลอดภัยง่าย

cd ไปยังไดเรกทอรี

สร้างไดเรกทอรีชั่วคราว

mv *.yourExlusionSelector.* ./temp
rm *
mv ./temp ./
rm -rf ./temp

เสร็จแล้ว


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