Unix: วิธีลบไฟล์ที่อยู่ในไฟล์


92

ฉันมีไฟล์ข้อความยาวพร้อมรายการมาสก์ไฟล์ที่ฉันต้องการลบ

ตัวอย่าง:

/tmp/aaa.jpg
/var/www1/*
/var/www/qwerty.php

ฉันต้องการลบมัน ลอง rm `cat 1.txt` แล้วมันบอกว่ารายการยาวเกินไป

พบคำสั่งนี้ แต่เมื่อฉันตรวจสอบโฟลเดอร์จากรายการบางรายการยังมีไฟล์ xargs rm <1.txtManual rm call จะลบไฟล์ออกจากโฟลเดอร์ดังกล่าวดังนั้นจึงไม่มีปัญหากับสิทธิ์


8
แม้ว่าจะหกปีต่อมา: คุณจะเข้าใจคำตอบข้อใดข้อหนึ่งหรือไม่? สิ่งนี้จะทำเครื่องหมายคำถามว่าได้รับการแก้ไขแล้วและช่วยเหลือผู้ใช้รายอื่นด้วย
MERose

คำตอบ:


116

สิ่งนี้ไม่ค่อยมีประสิทธิภาพ แต่จะใช้งานได้หากคุณต้องการรูปแบบ glob (เช่นใน / var / www / *)

for f in $(cat 1.txt) ; do 
  rm "$f"
done

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

xargs rm < 1.txt

4
จะเกิดอะไรขึ้นกับโซลูชันแรก (โดยใช้ CAT) หากเส้นทางมีช่องว่าง
a.dibacco

58

สมมติว่ามีรายชื่อไฟล์อยู่ในไฟล์1.txtให้ทำ:

xargs rm -r <1.txt

-rตัวเลือกที่ทำให้เกิดการเรียกซ้ำลงในไดเรกทอรีใด ๆ 1.txtที่มีชื่ออยู่ใน

หากไฟล์ใด ๆ เป็นแบบอ่านอย่างเดียวให้ใช้-fตัวเลือกเพื่อบังคับให้ลบ:

xargs rm -rf <1.txt

ระมัดระวังการป้อนข้อมูลไปยังเครื่องมือใด ๆที่ทำการลบแบบเป็นโปรแกรม ตรวจสอบให้แน่ใจว่าไฟล์ที่ระบุชื่อในไฟล์อินพุตนั้นต้องการลบจริงๆ ระมัดระวังเป็นพิเศษเกี่ยวกับการพิมพ์ผิดที่ดูเหมือนง่าย ตัวอย่างเช่นหากคุณใส่ช่องว่างระหว่างไฟล์และส่วนต่อท้ายไฟล์นั้นจะปรากฏเป็นชื่อไฟล์สองชื่อ:

file .txt

เป็นไฟล์สองไฟล์ที่แยกจากกัน: fileและ.txt.

สิ่งนี้อาจดูไม่อันตรายนัก แต่หากพิมพ์ผิดเป็นดังนี้:

myoldfiles *

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


1
"myoldfiles /" หรือ "/ tmp" ยิ่งหายนะด้วย -rf สังเกตอักขระช่องว่างถัดจาก "/"
Ray

24

ใช้สิ่งนี้:

while IFS= read -r file ; do rm -- "$file" ; done < delete.list

หากคุณต้องการขยาย glob คุณสามารถละเว้นการอ้างถึง$file:

IFS=""
while read -r file ; do rm -- $file ; done < delete.list

แต่ขอเตือนว่าชื่อไฟล์อาจมีเนื้อหาที่ "มีปัญหา" และฉันจะใช้เวอร์ชันที่ไม่มีการอ้างสิทธิ์ ลองนึกภาพรูปแบบนี้ในไฟล์

*
*/*
*/*/*

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


3
ขณะนี้เป็นคำตอบเดียวที่จับทั้งหมดของ/My Dir With Spaces/ /Spaces and globs/*.txt, --file-with-leading-dashesและเป็นโบนัสมัน POSIX และทำงานบน GNU / Linux, MacOS และ BSD
ผู้ชายคนนั้น

17

คุณสามารถใช้ '\ n' เพื่อกำหนดอักขระบรรทัดใหม่เป็นตัวคั่น

xargs -d '\n' rm < 1.txt

ระวัง -rf เพราะมันสามารถลบสิ่งที่คุณไม่ต้องการได้หาก 1.txt มีพา ธ ที่มีช่องว่าง นั่นเป็นเหตุผลที่ตัวคั่นบรรทัดใหม่ปลอดภัยกว่าเล็กน้อย

ในระบบ BSD คุณสามารถใช้ตัวเลือก -0 เพื่อใช้อักขระบรรทัดใหม่เป็นตัวคั่นดังนี้:

xargs -0 rm < 1.txt

1
บน OS X สิ่งนี้ทำให้ฉันได้รับxargs: illegal option -- d
waldyrious

จุดดี. ดูเหมือนว่าจะไม่มีตัวเลือกอื่นนอกจาก-0OS X
Ray

2
xargs -I_ rm _ยังใช้งานได้ใน OS X :) ดูstackoverflow.com/a/39335402/266309
waldyrious

หากใช้ BSD xargs (โดยที่ไม่มี-d) คุณสามารถแปลง newlines เป็น null ได้ก่อน:tr '\n' '\0' < 1.txt | xargs -0 rm
OrangeDog

15

คุณสามารถใช้ซับเดียวนี้:

cat 1.txt | xargs echo rm | sh

ซึ่งทำการขยายเชลล์ แต่ดำเนินrmการตามจำนวนครั้งต่ำสุด


ตราบใดที่การขยายตัวใด ๆ ไม่ยาวเกินไป?
Douglas Leeder

1
จริง glob สามารถสร้างรายการอาร์กิวเมนต์ที่ยาวเกินไป - คุณสามารถเพิ่ม-n <n>อาร์กิวเมนต์เพื่อxargsลดจำนวนอาร์กิวเมนต์ที่ส่งผ่านไปยังแต่ละ rm ได้ แต่จะยังไม่ปกป้องคุณจากลูกโลกเดียวที่เกินขีด จำกัด
tgdavies

13

xargs -I{} sh -c 'rm {}' < 1.txtควรทำในสิ่งที่คุณต้องการ ระวังคำสั่งนี้เนื่องจากรายการที่ไม่ถูกต้องในไฟล์นั้นอาจทำให้เกิดปัญหาได้มาก

คำตอบนี้ได้รับการแก้ไขหลังจาก @tdavies ชี้ให้เห็นว่าต้นฉบับไม่ได้ทำการขยายเชลล์


ขอบคุณ แต่ไม่จำเป็นต้องลบโฟลเดอร์เพียงไฟล์
Alexander

2
ลูกโลกจะไม่ขยายตัวเนื่องจากไม่เคย 'เห็น' จากเปลือกหอย
tgdavies

@tdavies ว้าว - คุณพูดถูก คำสั่งนี้ (แม้ว่าจะค่อนข้างผิดปกติ) จะใช้งานได้:xargs -I{} sh -c 'rm {}' < 1.txt
Mark Drago

4

ในกรณีนี้โดยเฉพาะเนื่องจากอันตรายที่อ้างถึงในคำตอบอื่น ๆ ฉันจะทำ

  1. แก้ไขในเช่น Vim และ:%s/\s/\\\0/gหลีกเลี่ยงอักขระเว้นวรรคทั้งหมดด้วยแบ็กสแลช

  2. จากนั้น:%s/^/rm -rf /ป้อนคำสั่งล่วงหน้า ด้วย-rคุณจะได้ไม่ต้องกังวลว่าจะมีการระบุไว้ไดเรกทอรีหลังจากที่ไฟล์ที่อยู่ในนั้นและ-fมันจะไม่บ่นเนื่องจากไฟล์หายไปหรือรายการที่ซ้ำกัน

  3. เรียกใช้คำสั่งทั้งหมด: $ source 1.txt


Spaces ไม่ใช่อักขระเพียงตัวเดียวที่ต้องใช้ Escape แต่เป็นที่นิยมในชื่อไฟล์ยังเป็นวงเล็บชนิดใดก็ได้ที่อาจนำไปสู่การขยายที่ไม่ต้องการ
emk2203

4

cat 1.txt | xargs rm -f | bash รันคำสั่งจะทำสิ่งต่อไปนี้สำหรับไฟล์เท่านั้น

cat 1.txt | xargs rm -rf | bash เรียกใช้คำสั่งจะทำพฤติกรรมซ้ำดังต่อไปนี้


2

เพื่อให้เป็นอีกวิธีหนึ่งคุณสามารถใช้คำสั่งต่อไปนี้

$ cat to_remove
/tmp/file1
/tmp/file2
/tmp/file3
$ rm $( cat to_remove )

1

นี่คืออีกตัวอย่างการวนซ้ำ อันนี้ยังมี 'if-statement' เป็นตัวอย่างในการตรวจสอบว่ารายการนั้นเป็น 'file' (หรือ 'directory' เป็นต้น):

for f in $(cat 1.txt); do if [ -f $f ]; then rm $f; fi; done

0

ที่นี่คุณสามารถใช้ชุดของโฟลเดอร์จากdeleteelist.txtในขณะที่หลีกเลี่ยงรูปแบบบางอย่างเช่นกัน

foreach f (cat deletelist.txt)
    rm -rf ls | egrep -v "needthisfile|*.cpp|*.h"
end

0

ซึ่งจะทำให้ชื่อไฟล์มีช่องว่าง (ตัวอย่างที่ทำซ้ำได้)

# Select files of interest, here, only text files for ex.
find -type f -exec file {} \; > findresult.txt
grep ": ASCII text$" findresult.txt > textfiles.txt
# leave only the path to the file removing suffix and prefix
sed -i -e 's/:.*$//' textfiles.txt
sed -i -e 's/\.\///' textfiles.txt

#write a script that deletes the files in textfiles.txt
IFS_backup=$IFS
IFS=$(echo "\n\b")
for f in $(cat textfiles.txt); 
do 
rm "$f"; 
done
IFS=$IFS_backup

# save script as "some.sh" and run: sh some.sh

0

ในกรณีที่มีคนชอบsedและลบโดยไม่ต้องขยายสัญลักษณ์แทน :

sed -e "s/^\(.*\)$/rm -f -- \'\1\'/" deletelist.txt | /bin/sh

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

และเพื่อความสมบูรณ์เช่นเดียวกันกับawk:

awk '{printf "rm -f -- '\''%s'\''\n",$1}' deletelist.txt | /bin/sh

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

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