यूनिक्स: किसी फ़ाइल में सूचीबद्ध फ़ाइलों को कैसे हटाएं


92

मेरे पास एक लंबी पाठ फ़ाइल है जिसमें मैं फ़ाइल मास्क की सूची को हटाना चाहता हूं

उदाहरण:

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

मुझे उन्हें हटाने की आवश्यकता है। Rm `बिल्ली 1.txt` की कोशिश की और यह सूची बहुत लंबी है।

यह आदेश मिला, लेकिन जब मैं सूची से फ़ोल्डर्स की जांच करता हूं, तो उनमें से कुछ के पास अभी भी फाइलें हैं xargs rm <1.txtमैनुअल आरएम कॉल ऐसे फ़ोल्डरों से फाइलें निकालता है, इसलिए अनुमति के साथ कोई समस्या नहीं है।


8
भले ही यह छह साल बाद हो: क्या आप किसी एक उत्तर को गलत मान लेंगे? यह प्रश्न को हल के रूप में चिह्नित करेगा और अन्य उपयोगकर्ताओं को भी मदद करेगा।
17'17

जवाबों:


116

यह बहुत कुशल नहीं है, लेकिन अगर आपको ग्लोब पैटर्न की जरूरत है (जैसे / 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 के साथ और भी अधिक विनाशकारी। "/" के बगल में स्थित अंतरिक्ष वर्ण पर ध्यान दें।
रे

24

इसे इस्तेमाल करो:

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

यदि आपको ग्लोब विस्तार की आवश्यकता है तो आप उद्धृत करना छोड़ सकते हैं $file:

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

लेकिन चेतावनी दी जाती है कि फ़ाइल नामों में "समस्याग्रस्त" सामग्री हो सकती है और मैं निर्विवाद संस्करण का उपयोग करूंगा। फ़ाइल में इस पैटर्न की कल्पना करें

*
*/*
*/*/*

यह वर्तमान निर्देशिका से काफी हटा देगा! मैं आपको डिलीट लिस्ट को इस तरह से तैयार करने के लिए प्रोत्साहित करूंगा कि ग्लोब पैटर्न की अब कोई आवश्यकता नहीं है, और फिर मेरे पहले उदाहरण की तरह उद्धरण का उपयोग करें


3
यह वर्तमान में केवल जवाब है कि हैंडल के सभी /My Dir With Spaces/ /Spaces and globs/*.txt, --file-with-leading-dashesऔर एक बोनस यह जीएनयू / लिनक्स, MacOS और BSD पर POSIX और काम करता है के रूप में।
वह अन्य लड़का

17

आप नई रेखा के चरित्र को सीमांकक के रूप में परिभाषित करने के लिए '\ n' का उपयोग कर सकते हैं।

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

-Rf के साथ सावधान रहें क्योंकि यह हटा सकता है कि आप क्या करना चाहते हैं यदि 1.txt में रिक्त स्थान के साथ पथ हैं। इसीलिए नई लाइन थोड़ा सुरक्षित है।

बीएसडी सिस्टम पर, आप इस तरह के सीमांकक के रूप में नई लाइन वर्णों का उपयोग करने के लिए -0 विकल्प का उपयोग कर सकते हैं:

xargs -0 rm < 1.txt

1
ओएस एक्स पर यह मुझे मिलता हैxargs: illegal option -- d
वाल्ड्रियस

अच्छी बात। ऐसा लगता है कि -0OS X पर कोई अन्य विकल्प नहीं है।
Ray

2
xargs -I_ rm _OS X में भी काम करता है :) देखें stackoverflow.com/a/39335402/266309
waldyrious

यदि BSD xargs (जहाँ कोई नहीं है -d) का उपयोग करते हुए , आप सबसे पहले nulls में न्यूलाइन को बदल सकते हैं:tr '\n' '\0' < 1.txt | xargs -0 rm
OrangeDog

15

आप इस एक-लाइनर का उपयोग कर सकते हैं:

cat 1.txt | xargs echo rm | sh

जो शेल विस्तार करता है लेकिन rmन्यूनतम संख्या को निष्पादित करता है।


जब तक किसी भी विस्तार बहुत लंबा नहीं है?
डगलस लीडर

1
सच है, एक ग्लोब एक तर्क सूची का उत्पादन कर सकता है जो बहुत लंबा है - आप प्रत्येक आरएम को दिए गए तर्कों की संख्या को कम -n <n>करने के xargsलिए तर्क जोड़ सकते हैं , लेकिन यह अभी भी आपको एक एकल ग्लोब से बचाएगा जो सीमा से अधिक है।
tgdavies

13

xargs -I{} sh -c 'rm {}' < 1.txtआपको जो चाहिए वो करना चाहिए। इस आदेश के साथ सावधान रहें क्योंकि उस फ़ाइल में एक गलत प्रविष्टि बहुत परेशानी पैदा कर सकती है।

यह जवाब @tdavies द्वारा इंगित करने के बाद संपादित किया गया था कि मूल ने शेल विस्तार नहीं किया था।


धन्यवाद, लेकिन फ़ोल्डर्स को हटाने की कोई जरूरत नहीं है, केवल फाइलें
अलेक्जेंडर

2
ग्लब्स का विस्तार नहीं होगा, क्योंकि वे शेल द्वारा कभी भी 'देखे' नहीं जाते हैं।
tgdavies

@tdavies वाह - तुम सही हो। यह कमांड (थोड़ा बदसूरत) काम करेगा:xargs -I{} sh -c 'rm {}' < 1.txt
मार्क Drago

4

इस विशेष मामले में, अन्य उत्तरों में उद्धृत खतरों के कारण, मैं करूंगा

  1. उदाहरण के लिए विम में संपादित करें और :%s/\s/\\\0/g, बैकस्लैश के साथ सभी अंतरिक्ष वर्णों को छोड़कर।

  2. फिर :%s/^/rm -rf /, कमांड को प्रिपेंड कर रहा है। इसके साथ -rआपको इसमें निहित फ़ाइलों के बाद निर्देशिकाओं को सूचीबद्ध करने की चिंता करने की आवश्यकता नहीं है, और इसके साथ -fलापता फ़ाइलों या डुप्लिकेट प्रविष्टियों के कारण शिकायत नहीं होगी।

  3. सभी आदेश चलाएँ: $ source 1.txt


स्पेस केवल एकमात्र पात्र नहीं हैं, जिन्हें भागने की जरूरत है, फ़ाइल नाम में लोकप्रिय भी किसी भी तरह के ब्रैकेट हैं जो अवांछित विस्तार का कारण बन सकते हैं।
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

यहाँ एक और लूपिंग उदाहरण है। इस प्रविष्टि में एक 'फ़ाइल' (या उदाहरण के लिए 'निर्देशिका') है या नहीं यह देखने के लिए जाँच के उदाहरण के रूप में एक 'इफ-स्टेटमेंट' भी शामिल है:

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

0

यहाँ आप से फ़ोल्डरों के सेट का उपयोग कर सकते deletelist.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

यदि एकल उद्धरण हटाए जाते हैं तो वाइल्डकार्ड विस्तार काम करेगा, लेकिन फ़ाइल नाम में रिक्त स्थान होने पर यह खतरनाक है। इसके लिए वाइल्डकार्ड के आसपास उद्धरण जोड़ने की आवश्यकता होगी।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.