फ़ाइल को हटा दें लेकिन किसी सूची की सभी फ़ाइलों को बाहर कर दें


17

मुझे समय-समय पर एक फ़ोल्डर को साफ करने की आवश्यकता होती है। मुझे एक फ़िलालिस्ट मिला जिसमें टेक्स्ट है, कौन सी फ़ाइल्स की अनुमति है। अब मुझे उन सभी फ़ाइलों को हटाना होगा जो इस फ़ाइल में नहीं हैं।

उदाहरण:

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
गुजरात संताना

2
@ गुर्जरात हम मुफ्त होमवर्क सेवा नहीं हैं, इसलिए टिप्पणी उचित है। प्रश्न के लिए ही, यह दूसरों के लिए उपयोगी हो सकता है, इसलिए यह अब तक खुला है।
सेर्गेई कोलोडियाज़नी

@ मैं पूरी तरह से आपसे सहमत हूँ
गुजरात संताना

जवाबों:


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यदि आप जानना चाहते हैं कि क्या कोई मैच था या नहीं , तो आउटपुट का बेकार कैप्चरिंग । मैंने मुद्दों से बचने के लिए फिक्स्ड-स्ट्रिंग पैटर्न का भी उपयोग किया।
डेविड फ़ॉस्टर

@DavidFoerster योगदान के लिए धन्यवाद। हालांकि, जब आप बदल whileएक करने के लिए लूप forलूप यदि आपने अनजाने में बदल iteration keyसे iकरने के लिए f। घोषणा में, जिसने कोड को तोड़ दिया। मैंने ठीक कर दिया।
LD जेम्स

उफ़, आदत का बल। मैं फ़ाइल नामों के लिए शेल चर नामों को संक्षिप्त करता हूं f। ; -पी (… और आपके जवाब के लिए जिसे मैं पहले भूल गया।)
डेविड फ़ॉस्टर

10

यह अजगर स्क्रिप्ट ऐसा कर सकती है:

#!/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 (n) लुक-अप के बजाय O (1) के लिए एक सूची के बजाय उपयोग करने के लिए आपका कोड बदल दिया ।
डेविड फोस्टरस्टर

आपकी मदद के लिए धन्यवाद, मैं सामान्य रूप से एक खिड़कियों वाला आदमी हूं, लेकिन अजगर
सीना

1
@ stefan83: पायथन सिर्फ विंडोज पर चलता है।
डेविड फ़ॉस्टर

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-pविकल्प बलों xargsको क्रियान्वित करने से पहले पुष्टि करने के लिए पूछने के लिए।

आपकी मदद के लिए thx, अब मेरे पास मेरा समाधान है!
stefan83

@gardenhead, मैंने आपका कोड थक गया है लेकिन यह निर्देशिका की सभी फ़ाइलों को हटा देता है और केवल पहली और अंतिम फ़ाइल को न हटाए जाने वाली सूची में रखता है। क्या आपके पास इस समस्या के लिए कोई विचार है? अग्रिम में धन्यवाद।
नेगर

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]} )

(बैश के mapfileबिलिन के बराबर - या उसका पर्यायवाची 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

यह मानते हुए कि आपके बैश शेल में extglob shoptसेट है, यहाँ कुछ अधिक रूढ़िवादी विकल्प है:

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

(@ साथ में @ बाग़ का अन्यथा शानदार कॉम सुझाव!)


0

जब तक अधिकतम शेल तर्क सीमा से ls /home/me/myfolder2tocleanup/अधिक का उत्पादन नहीं होता है जो उबंटू के लिए लगभग 2 एमबी है, मैं निम्नलिखित सुझाव दूंगा। ARG_MAX


एक लाइन कमांड कार्यान्वयन जो काम करेगा, वह इस प्रकार होगा:

  1. dont-delete.txtफाइल को उस डायरेक्टरी में कॉपी करें, जिसमें डिलीट की जाने वाली फाइल्स हों जैसे:
cp dont-delete.txt /home/me/myfolder2tocleanup/
  1. cd इस तरह से हटाई जाने वाली फ़ाइलों वाली निर्देशिका:
cd /home/me/myfolder2tocleanup/
  1. कमांड का परीक्षण करने के लिए एक ड्राई-रन करें और इसे उन फ़ाइलों के नाम प्रिंट करें जिन्हें यह पता चलता है कि वास्तव में उन्हें हटाने के बिना डिलीट किया जाना चाहिए, जैसे:
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

explaination:

  • ls -pवर्तमान निर्देशिका में सभी फ़ाइलों और निर्देशिकाओं को सूचीबद्ध करेगा और विकल्प निर्देशिका नामों में -pएक जोड़ देगा /
  • grep -v /निर्देशिकाओं को /उनके नामों में शामिल सभी वस्तुओं को हटाकर बाहर करेगा ।
  • sed 's/\<dont-delete.txt\>//g'dont-delete.txtफ़ाइल को बाहर कर देगा , इसलिए यह प्रक्रिया में हटाया नहीं जाता है।
  • sortहोगा, बस सुनिश्चित करने के लिए, शेष उत्पादन को क्रमबद्ध करें ls
  • comm -3 - <(sort dont-delete.txt)dont-delete.txtफ़ाइल को सॉर्ट करेगा , इसे lsउन दोनों के मौजूद फिल्टनाम के छांटे गए आउटपुट से तुलना करेगा ।
  • xargs rmके पहले से ही संसाधित आउटपुट में शेष सभी फ़ाइलनामों को हटा देगा ls। सभी मौजूदा निर्देशिका में आइटम के अलावा हटा दिया जाएगा यह साधन निर्देशिका , में सूचीबद्ध फ़ाइलों 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उन फ़ाइलों को हटाने के लिए ऊपर दिए गए कमांड में जोड़ें , जो कि एक्सेलिस्ट फाइल में मौजूद नहीं हैं । यदि आपके पास -deleteविकल्प नहीं है, तो आप निम्न के rmसाथ उपयोग कर सकते हैं -exec:

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

या इसके बजाय टर्मिनेटर के साथ उपयोग -execकरना+

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हटा दिया जाएगा।


मैंने एक नई पंक्ति द्वारा अलग किए गए फ़ाइल नामों की एक पाठ फ़ाइल के साथ यह कोशिश की। इसने निर्देशिका की सभी फ़ाइलों को हटा दिया।
जैक्स मालप्रेड

मुझे लगता है कि आपकी "कीप लिस्ट" गलत थी।
nyxz

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