मुझे कैसे पता चलेगा कि कौन सी फाइलें किसी सूची से गायब हैं?


9

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

for f in $(cat file_list); do
find . -name $f > /dev/null || print $f
done

(का उपयोग करते हुए zsh) लेकिन यह काम नहीं करता है क्योंकि यह फ़ाइल findसे बाहर निकलता 0है या नहीं। मुझे लगता है कि मैं इसे किसी अन्य परीक्षण के माध्यम से पारित कर सकता हूं जो यह देखने के लिए परीक्षण करता है कि क्या findकोई आउटपुट (क्रूड लेकिन प्रभावी के > /dev/nullसाथ बदलने के लिए होगा |grep '') का उत्पादन होता है, लेकिन ऐसा लगता है कि बकरी को पकड़ने के लिए ट्रोल का उपयोग करना (अन्य राष्ट्रीयताओं को स्लेजहैमर और अखरोट के बारे में कुछ कहना हो सकता है) )।

क्या findमुझे उपयोगी निकास मूल्य देने के लिए ज़बरदस्ती करने का कोई तरीका है ? या कम से कम उन फ़ाइलों की सूची प्राप्त करने के लिए जो नहीं मिलीं? (मैं तार्किक संयोजकों के कुछ चालाक विकल्प द्वारा उत्तरार्द्ध को शायद अधिक आसान होने की कल्पना कर सकता हूं, लेकिन मुझे लगता है कि जब मैं इसका पता लगाने की कोशिश करता हूं तो मैं हमेशा गाँठ में बंध जाता हूं।)

पृष्ठभूमि / प्रेरणा: मेरे पास "मास्टर" बैकअप है और मैं यह जांचना चाहता हूं कि मेरे स्थानीय मशीन पर कुछ फाइलें मेरे मास्टर बैकअप पर मौजूद हैं उन्हें हटाने से पहले (थोड़ा स्थान बनाने के लिए)। इसलिए मैंने फाइलों की एक सूची बनाई, sshउन्हें मास्टर मशीन में एड किया, और फिर लापता फाइलों को खोजने के लिए सबसे अच्छा तरीका पता लगाने के लिए एक नुकसान में था।


मैंने तेजी से उपयोग करने के लिए अपने समाधान को अद्यतन किया locate
उपयोगकर्ता अज्ञात

@userunknown locateफाइल सिस्टम की वर्तमान स्थिति नहीं दिखा रहा है, यह एक दिन, या एक सप्ताह पुराना भी हो सकता है। यह बैकअप परीक्षण के लिए आधार के रूप में उपयुक्त है।
वोल्कर सीगल

जवाबों:


5

findसफलता का एक विशेष मामला है (कोई त्रुटि नहीं हुई) खोजने पर विचार करता है। यह जांचने का एक सामान्य तरीका है कि फाइलें कुछ findमानदंडों से मेल खाती हैं या नहीं, यह जांचने के लिए कि क्या आउटपुट findखाली है। बेहतर दक्षता के लिए, जब मैचिंग फाइलें होती हैं, तो -quitजीएनयू पर प्रयोग करके इसे पहले मैच में छोड़ दिया जाता है, या head( head -c 1यदि उपलब्ध हो, अन्यथा head -n 1जो मानक है) अन्य सिस्टम पर इसे लंबे आउटपुट के बजाय टूटे हुए पाइप से मरने के लिए बनाते हैं।

while IFS= read -r name; do
  [ -n "$(find . -name "$name" -print | head -n 1)" ] || printf '%s\n' "$name"
done <file_list

बैश b4 या zsh में, आपको findएक साधारण नाम मिलान के लिए बाहरी कमांड की आवश्यकता नहीं है : आप इसका उपयोग कर सकते हैं **/$name। बैश संस्करण:

shopt -s nullglob
while IFS= read -r name; do
  set -- **/"$name"
  [ $# -ge 1 ] || printf '%s\n' "$name"
done <file_list

एक समान सिद्धांत पर Zsh संस्करण:

while IFS= read -r name; do
  set -- **/"$name"(N)
  [ $# -ge 1 ] || print -- "$name"
done <file_list

या यहां एक पैटर्न से मेल खाते फ़ाइल के अस्तित्व का परीक्षण करने का एक छोटा लेकिन अधिक गूढ़ तरीका है। ग्लोब क्वालीफायर Nआउटपुट को खाली कर देता है अगर कोई मैच नहीं होता है, [1]केवल पहला मैच बरकरार रखता है, और मिलान किए गए फ़ाइल नाम के बजाय e:REPLY=true:प्रत्येक मैच का विस्तार करने के लिए बदलता है 1। तो अगर कोई मैच है, या सिर्फ अगर कोई मैच नहीं है तो **/"$name"(Ne:REPLY=true:[1]) falseफैलता है ।true falsefalse

while IFS= read -r name; do
  **/"$name"(Ne:REPLY=true:[1]) false || print -- "$name"
done <file_list

अपने सभी नामों को एक खोज में संयोजित करना अधिक कुशल होगा। यदि कमांड लाइन पर आपके सिस्टम की लंबाई सीमा के लिए पैटर्न की संख्या बहुत बड़ी नहीं है, तो आप आउटपुट के साथ सभी नामों को जोड़ सकते हैं -o, एकल findकॉल कर सकते हैं और पोस्ट-प्रोसेस कर सकते हैं। यदि नामों में से कोई भी शेल मेटाचैकर नहीं है (ताकि नाम findपैटर्न के रूप में अच्छी तरह से हों), यहाँ awk (अप्रकाशित) के साथ पोस्ट-प्रोसेस करने का एक तरीका है:

set -o noglob; IFS='
'
set -- $(<file_list sed -e '2,$s/^/-o\
/')
set +o noglob; unset IFS
find . \( "$@" \) -print | awk -F/ '
    BEGIN {while (getline <"file_list") {found[$0]=0}}
    wanted[$0]==0 {found[$0]=1}
    END {for (f in found) {if (found[f]==0) {print f}}}
'

एक अन्य दृष्टिकोण पर्ल का उपयोग करना होगा और File::Find, जिससे एक निर्देशिका में सभी फ़ाइलों के लिए पर्ल कोड को चलाना आसान हो जाएगा।

perl -MFile::Find -l -e '
    %missing = map {chomp; $_, 1} <STDIN>;
    find(sub {delete $missing{$_}}, ".");
    print foreach sort keys %missing'

वैकल्पिक दृष्टिकोण दोनों पक्षों पर फ़ाइल नामों की एक सूची तैयार करना और एक पाठ तुलना पर काम करना है। Zsh संस्करण:

comm -23 <(<file_list sort) <(print -rl -- **/*(:t) | sort)

मैं इसे दो कारणों से स्वीकार कर रहा हूं। मुझे सिंटैक्स के zshसाथ समाधान पसंद है **। यह एक बहुत ही सरल उपाय है और मशीन के संदर्भ में यह सबसे अधिक कुशल नहीं हो सकता है , यह वास्तव में मुझे याद रखने के मामले में सबसे अधिक कुशल है! इसके अलावा, यहां पहला समाधान इस वास्तविक प्रश्न का उत्तर देता है कि यह findकिसी ऐसी चीज में बदल जाता है, जहां से बाहर निकलने वाला कोड "मुझे एक मैच नहीं मिला" से "मुझे एक मैच मिला"।
एंड्रयू स्टेसी

9

आप यह statनिर्धारित करने के लिए उपयोग कर सकते हैं कि फाइल सिस्टम पर मौजूद है या नहीं।

यदि फ़ाइल मौजूद हैं, तो आपको परीक्षण करने के लिए अंतर्निहित शेल फ़ंक्शन का उपयोग करना चाहिए ।

while read f; do
   test -f "$f" || echo $f
done < file_list

"परीक्षण" वैकल्पिक है और स्क्रिप्ट वास्तव में इसके बिना काम करेगी, लेकिन मैंने इसे पठनीयता के लिए छोड़ दिया।

संपादित करें: यदि आपके पास बिना रास्तों के फ़ाइल नाम की सूची के लिए काम करने के अलावा कोई विकल्प नहीं है, तो मैं आपको सुझाव देता हूं कि फाइल्स के साथ एक बार फाइलों की एक सूची बनाएं, फिर इसे grep के साथ पुन: व्यवस्थित करें कि कौन सी फाइलें हैं।

find -type f /dst > $TMPFILE
while read f; do
    grep -q "/$f$" $TIMPFILE || echo $f
done < file_list

ध्यान दें कि:

  • फ़ाइल सूची में केवल निर्देशिका नहीं फ़ाइलें शामिल हैं,
  • grep मैच पैटर्न में स्लैश है, इसलिए हम पूर्ण फ़ाइल नामों की तुलना करते हैं जो कि विभाजन नहीं हैं,
  • और खोज पैटर्न में अंतिम '$' लाइन के अंत से मेल खाना है, ताकि आपको निर्देशिका मिलान न मिले, केवल पूर्ण फ़ाइल नाम पैच।

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

हममम। हां आपने यह नहीं कहा कि आपके पास बिना रास्तों के फ़ाइल नाम थे! हो सकता है कि आप इसके बजाय THAT समस्या को ठीक कर सकते हैं? यह एक ही डाटासेट में कई बार एक गुच्छा खोजने की तुलना में अधिक कुशल होगा।
कालेब

संपादन के लिए धन्यवाद, और विशिष्ट नहीं होने के लिए फिर से क्षमा करें। फ़ाइल का नाम / पथ कुछ ऐसा नहीं है जिसे मैं ठीक करने जा रहा हूं - फाइलें दो प्रणालियों पर अलग-अलग जगहों पर हो सकती हैं, इसलिए मैं एक ऐसा समाधान चाहता हूं जो कि चारों ओर काम करने के लिए पर्याप्त मजबूत हो। कंप्यूटर को मेरी विशिष्टताओं पर काम करना चाहिए , न कि दूसरे तरीके से! गंभीरता से, यह कुछ ऐसा नहीं है जो मैं अक्सर करता हूं - मैं जगह बनाने के लिए हटाने के लिए कुछ पुरानी फ़ाइलों की तलाश कर रहा था और बस यह सुनिश्चित करने के लिए "त्वरित" एन 'गंदा' तरीका चाहता था कि वे मेरे बैकअप में थे।
एंड्रयू स्टेसी

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

एके! मैंने इस सवाल पर ध्यान केंद्रित करने की कोशिश करने के लिए विवरणों का एक भार छोड़ दिया और आप उन मान्यताओं के भार से भर रहे हैं - जो मुझे कहना चाहिए - पूरी तरह से उचित हैं लेकिन पूरी तरह से गलत हैं! यह कहने के लिए पर्याप्त है कि मुझे पता है कि यदि फ़ाइल वहाँ है और किसी विशेष प्रकार के नाम वाली निर्देशिका में है तो मुझे पता है कि यह मूल फ़ाइल है और मेरी मशीन पर प्रतिलिपि को हटाना सुरक्षित है।
एंड्रयू स्टेसी

1

पहला, सरलीकृत दृष्टिकोण, हो सकता है:

क) अपने फाइलिस्ट को छाँटें:

sort file.lst > sorted.lst 
for f in $(< sortd.lst) ; do find -name $f -printf "%f\n"; done > found.lst
diff sorted.lst found.lst

मिसिंग खोजने के लिए, या

comm sorted.lst found.lst

मैच खोजने के लिए

  • नुकसान:
    • फ़ाइल नाम में नई कहानियों को संभालना बहुत कठिन है
    • फ़ाइलनामों में रिक्त और इसी तरह की चीजें भी अच्छी नहीं हैं। लेकिन जब से आप फ़ाइलों की सूची में फ़ाइलों पर नियंत्रण रखते हैं, शायद यह समाधान पहले से ही पर्याप्त है, हालांकि ...
  • कमियां:

    • जब कोई फ़ाइल ढूंढता है, तो वह एक और एक को खोजने के लिए दौड़ता रहता है। आगे की खोज को छोड़ना अच्छा होगा।
    • कुछ तैयारी के साथ एक साथ कई फाइलों को खोज सकते हैं:

      find -name a.file -or -name -b.file -or -name c.file ...

एक विकल्प मिल सकता है? फिर, मान ली गई फ़ाइलों की एक निर्धारित सूची:

 for f in $(< sorted.tmp) ; do locate --regexp "/"$f"$" > /dev/null || echo missing $f ; done

Foo.bar के लिए एक खोज a- फ़ाइल foo.ba से मेल नहीं खाएगी, या oo.bar के साथ --regexp-construct (p के बिना regex द्वारा भ्रमित नहीं होना)।

आप खोज के लिए एक विशिष्ट डेटाबेस निर्दिष्ट कर सकते हैं, और आपको खोज से पहले इसे अपडेट करना होगा, यदि आपको हाल के परिणामों की आवश्यकता है।


1

मुझे लगता है कि यह उपयोगी भी हो सकता है।

यह एक पंक्ति समाधान है, यदि आप अपनी "सूची" के लिए चुनते हैं तो वास्तविक फाइलें हैं जिन्हें आप किसी अन्य फ़ोल्डर के साथ सिंक्रनाइज़ करना चाहते हैं:

function FUNCsync() { local fileCheck="$synchronizeTo/$1"; if [[ ! -f "$fileCheck" ]];then echo "$fileCheck";fi; };export -f FUNCsync;find "$synchronizeFrom/" -maxdepth 1 -type f -not -iname "*~" -exec bash -c 'FUNCsync "{}"' \; |sort

पढ़ने में मदद करने के लिए:

function FUNCsync() {
  local fileCheck="$synchronizeTo/$1";
  if [[ ! -f "$fileCheck" ]];then 
    echo "$fileCheck";
  fi; 
};export -f FUNCsync;
find "$synchronizeFrom/" -maxdepth 1 -type f -not -iname "*~" -exec bash -c 'FUNCsync "{}"' \; |sort

यह उदाहरण बैकअप "* ~" फ़ाइलों को निकालता है और नियमित फ़ाइल प्रकार "-type f" को सीमित करता है


0
FIND_EXP=". -type f \( "
while read f; do
   FIND_EXP="${FIND_EXP} -iname $f -or"
done < file_list
FIND_EXP="${var%-or}"
FIND_EXP="${FIND_EXP} \)"
find ${FIND_EXP}

शायद?


0

केवल परिणाम सूची की लंबाई के साथ क्वेरी सूची की लंबाई की तुलना क्यों नहीं की जाती है?

while read p; do
  find . -name $p 2>/dev/null
done < file_list.txt | wc -l
wc -l file_list.txt
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.