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


9

मेरे पास 1000+ फाइलों के साथ एक निर्देशिका है। एक पाठ फ़ाइल में, मेरे पास लगभग 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" या "कम" के साथ कर सकते हैं)।
फिर क्रिया करें:

sh -x rmscript

यदि फ़ाइलों के नाम में जगह है (यदि फ़ाइलों "के नाम में है तो यह काम नहीं करेगा):

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

बेशक फिल्म निर्माता एक ही निर्देशिका में नहीं होना चाहिए!

संपादित करें:

नाथन की फ़ाइल सूची में ऐसे नाम थे जो निर्देशिका की सभी फ़ाइलों (जैसे "html" "bob.html" से मेल खाते हैं) से मिलान कर रहे थे। इसलिए कुछ भी नहीं हटाया गया क्योंकि egrep -vfसभी स्ट्रीम को अवशोषित कर लिया। मैंने प्रत्येक फ़ाइल नाम के चारों ओर "^" और "$" लगाने की आज्ञा जोड़ी। मैं यहाँ भाग्यशाली था कि नाथन की फ़ाइल सूची सही थी। क्या यह सीआर-एलएफ समाप्त लाइनों के साथ या अतिरिक्त रिक्त स्थान के साथ प्रारूपित किया गया होता है, कोई भी फाइल एग्रेप द्वारा संरक्षित नहीं की जाती है और सभी को हटा दिया गया है।


जब मैं पूर्वावलोकन कमांड चलाता हूं, तो मुझे "rm" के साथ एक लाइन मिलती है। जब मैं वास्तविक कमांड चलाता हूं, तो मुझे rm के लिए लापता तर्क के बारे में एक त्रुटि संदेश मिलता है। क्या मुझे ls से परिणाम का उपयोग करने के लिए विशेष वाक्यविन्यास की आवश्यकता है? xargs इनपुट में egrep?
नाथन

@ नथन आपको पहले अपनी निर्देशिका में सीडी होना चाहिए। कोई विशेष वाक्य-विन्यास नहीं। lsनिर्देशिका फ़ाइल नाम प्रदान करता है, egrep -vf filelistअपने 50 फ़ाइल नामों को फ़िल्टर करें। मुझे डर है कि आपने अपनी सभी फाइलें हटा दी हैं।
इमैनुएल

@Emamanuel मैं उस डायरेक्टरी से कमांड चला रहा हूं जिसमें डिलीट की जाने वाली फाइलें हैं।
नाथन

@ नथन आपकी सभी फाइलें हटा दी गई हैं?
इमैनुएल

नहीं, वे अभी भी वहाँ हैं।
नाथन

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"

मुझे यह सबसे अच्छा लगता है क्योंकि यह
हिसाब से फिल्मकार

मेरे से +1, हालाँकि यह रिक्त स्थान के साथ बहुत अच्छा व्यवहार नहीं करता है। शायद कुछ एकल कोट्स ( ') को जोड़ा जाना चाहिए keep=( -name \'"$REPLY"\' )और keep+=( -o -name \'"$REPLY"\' )
क्रिस्टियन सियुपिटु

उपरोक्त खतरनाक है, क्योंकि आप गलती से फ़ाइलों को हटा सकते हैं।
द्विविवाह

@CristianCiupitu है ना? मैंने एक डेमो जोड़ा जिसमें दिखाया गया है कि यह व्हाट्सएप के साथ बहुत अच्छा व्यवहार करता है।
कोजीरो

@ दाविद किन परिस्थितियों में? किसी भी समय आप उन चीजों को हटाते हैं जिन्हें आप गलती करने का जोखिम चलाते हैं, लेकिन सवाल के मापदंडों के भीतर मुझे लगता है कि मेरा डेमो साबित करता है कि यह दृष्टिकोण ध्वनि है।
कोजिरो

1

के साथ zsh:

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

यह filelistकिसी ऐरे की पंक्तियों को पढ़ता है और फिर ग्लोब क्वालीफायर / eस्ट्रिंग का उपयोग ग्लोब / केवल फाइल के नाम का .चयन करता है जो एरे में मौजूद नहीं है: केवल रेगुलर फाइल्स का चयन करता है ( Dयदि आपकी सूची में डॉटफाइल्स शामिल हैं) और नेगेटिव ^e_'expression'_आगे केवल उन लोगों के लिए चयन करें जो कि अभिव्यक्ति गलत है, अर्थात यदि उनका नाम ( $REPLY) सरणी का एक तत्व नहीं है
यदि आप परिणाम से खुश हैं तो वास्तव में फ़ाइलों को हटाने के print -rlसाथ बदलें rm:

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

फ़ाइलों को पुनरावर्ती रूप से चुनने और हटाने के लिए, ग्लोब संशोधक वाले */**ग्लोब का उपयोग करें ${REPLY:t}:

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

0

यदि आप निर्देशिका की सामग्री को फ़ाइल में रखते हैं, जैसे:

cd <somedirectory>
ls >> 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कमांड का उपयोग करके डिलीट करने की जरूरत है और आउटपुट को 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

पुनश्च : संभवतः, यदि आप इसे स्क्रिप्ट के रूप में सहेजने और इसे चलाने की इच्छा रखते हैं, तो आप स्क्रिप्ट नाम का उपयोग करके भी जोड़ सकते हैं echo scriptname >> not_to_be_deleted_files

हालांकि इसकी आवश्यकता नहीं है, मैं इसे करना पसंद करता हूं क्योंकि बाद में कोई पछतावा नहीं होगा। मैंने फाइलों के एक छोटे समूह के लिए परीक्षण किया और यह मेरे सिस्टम में काम आया। हालाँकि, यदि आप निश्चित होना चाहते हैं, तो testपहले एक निर्देशिका में प्रयास करें और फिर मूल निर्देशिका में फ़ाइलों को हटा दें।


0
  • सूची को स्रोत के रूप में उपयोग करें, सूची की सभी फाइलों को एक नए, नए और खाली सेव-डायर में स्थानांतरित करने के लिए।
  • सूची में फ़ाइलों की संख्या और सहेजी गई फ़ाइलों की संख्या की तुलना करें।
  • यदि दोनों मेल खाते हैं, तो अपनी पसंदीदा विधि से सभी सहेजे न गए फाइलों को हटा दें।
  • सहेजी गई फ़ाइलों को वापस ले जाएं।

0

मैं सुरक्षित और अधिक, बहुत तेज़ दृष्टिकोण के लिए गया क्योंकि मेरे पास सूची में 18.000 फाइलें थीं! मुझे एक बड़े ड्रुपल इंस्टॉलेशन में छवियों को साफ करने की आवश्यकता थी।

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

तो एक उदाहरण पंक्ति होगी, अस्थायी गंतव्य होने के साथ:

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

यह इस संरचना का निर्माण करेगा:

temp
  misc
    feed.png

ध्यान दें कि डेस्टिनेटन को उसी फाइल सिस्टम में होना चाहिए जो हार्डलिंक के काम करने के स्रोत के रूप में हो।

अगला कदम स्क्रिप्ट का निर्माण करना है:

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

अब, मान लें कि आपने पहले से ही खाली dir / कुछ / जहाँ / temp बनाया है, आप फ़ाइलों को इस तरह से कॉपी कर सकते हैं:

sh newfilelist 2> missing_files

ध्यान दें कि त्रुटियों का अंत कैसे होता है missing_files। इस दृष्टिकोण का जोड़ा बोनस यह है कि आपको मूल सूची से फ़ाइलों की एक सूची मिलेगी जो वास्तव में मौजूद नहीं है!

स्क्रिप्ट चलाने के बाद, अस्थायी में केवल वे फ़ाइलें होंगी जो फ़ाइल सूची में हैं, लेकिन बिना कुछ हटाए और बिना अतिरिक्त स्थान उठाए। यदि आप परिणाम से संतुष्ट हैं, तो आप सबफ़ोल्डर सहित सभी मूल फ़ाइलों को हटा सकते हैं।

अंत में, अस्थायी स्थान पर फ़ाइलों और फ़ोल्डरों को मूल स्थान पर वापस ले जाएं।

18.000 फ़ाइलों के लिए इसमें केवल कुछ सेकंड लगते हैं।


0

सुरक्षित, सरल।

cd निर्देशिका के लिए।

एक अस्थायी निर्देशिका बनाएँ।

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

किया हुआ।


साइट पर आपका स्वागत है। जबकि आपका दृष्टिकोण काम करेगा यदि ओपी द्वारा उल्लिखित सूची पर नाम एक साधारण पैटर्न मिलान के परिणाम हैं - जो बहुत अच्छी तरह से मामला हो सकता है - कृपया ध्यान दें कि ओपी ने कहा कि बाहर करने के लिए फाइलनाम एक विशिष्ट फ़ाइल में संग्रहीत हैं; आप अपने उत्तर का विस्तार करना चाहते हैं ताकि एक स्थिर पैटर्न पर निर्भर होने के बजाय उस फ़ाइल से बहिष्करण पैटर्न को पढ़ सकें, या कंसोल पर संभावित कई पैटर्न कॉपी कर सकें।
एडमिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.