কোন তালিকা থেকে কোন ফাইলগুলি অনুপস্থিত তা আমি কীভাবে খুঁজে পাব?


9

আমার কাছে ফাইলগুলির একটি তালিকা রয়েছে যা আমি আমার ফাইল সিস্টেমে উপস্থিত রয়েছে কিনা তা যাচাই করতে চাই। আমি এটি ব্যবহার করে এটি করার কথা ভেবেছিলাম find:

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

(ব্যবহার করে zsh) তবে এটি কাজ করে না যা এটি ফাইলটি আবিষ্কার করে কিনা তা findপ্রস্থান 0করে। আমি অন্য কিছু পরীক্ষা যা কিনা তা দেখতে পরীক্ষা মাধ্যমে এটি পাস পারে findকোনো আউটপুট (অশোধিত কিন্তু কার্যকর প্রতিস্থাপন করতে হবে উৎপন্ন > /dev/nullসঙ্গে |grep '') কিন্তু একটি ছাগল ধরা একটি দানব ব্যবহার মত এই মতানুযায়ী (অন্যান্য জাতীয়তা sledgehammers এবং আখরোট সম্পর্কে কিছু বলতে পারে )।

findআমাকে একটি কার্যকর প্রস্থান মূল্য দেওয়ার জন্য বাধ্য করার কোনও উপায় আছে ? বা অন্তত সেই ফাইলগুলির তালিকা পাওয়া যায় নি যা পাওয়া যায় নি? (আমি লজিকাল সংযোগকারীগুলির কয়েকটি ধূর্ত ধরণের পছন্দ দ্বারা সম্ভবত আরও সহজ হওয়াটা কল্পনা করতে পারি, তবে আমি যখন এটি বের করার চেষ্টা করি তখন আমি সবসময় গিঁটে আবদ্ধ হতে পারি seem)

পটভূমি / অনুপ্রেরণা: আমার একটি "মাস্টার" ব্যাকআপ আছে এবং আমি আমার স্থানীয় মেশিনের কিছু ফাইল মুছে ফেলার আগে আমার মাস্টার ব্যাকআপে উপস্থিত রয়েছে (কিছুটা জায়গা তৈরি করতে) তা পরীক্ষা করতে চাই। সুতরাং আমি ফাইলগুলির একটি তালিকা তৈরি করে sshএটিকে মাস্টার মেশিনে এড করেছিলাম এবং তখন হারিয়ে যাওয়া ফাইলগুলি সন্ধান করার সর্বোত্তম উপায়টি খুঁজে বের করার জন্য ক্ষতির মধ্যে পড়েছিলাম ।


আমি আমার সমাধানটি আরও দ্রুত ব্যবহার করার জন্য আপডেট করেছি locate
ব্যবহারকারী অজানা

@ ইউজারুননড 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

বাশ ≥4 বা 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নিদর্শন হিসাবে থাকে), তবে এখানে জাজ (অনির্ধারিত) সহ পোস্ট-প্রক্রিয়া করার একটি উপায় রয়েছে:

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

"পরীক্ষা" isচ্ছিক এবং স্ক্রিপ্টটি আসলে এটি ছাড়া কাজ করবে, তবে আমি এটি পাঠযোগ্যতার জন্য রেখে দিয়েছি।

সম্পাদনা করুন: যদি আপনার কাছে সত্যিই কোনও পাথ ছাড়াই ফাইল নামগুলির তালিকার জন্য কাজ করা ছাড়া কোনও বিকল্প না থাকে, তবে আমি আপনাকে একবার অনুসন্ধানের সাথে ফাইলগুলির একটি তালিকা তৈরি করার পরামর্শ দিই, তবে কোন ফাইল রয়েছে তা নির্ধারণের জন্য গ্রেপের সাহায্যে এটি পুনরুক্ত করুন।

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

মনে রাখবেন যে:

  • ফাইল তালিকার মধ্যে কেবল ফাইল নয় ডিরেক্টরি রয়েছে,
  • গ্রেপ ম্যাচ প্যাটার্নে স্ল্যাশ তাই আমরা সম্পূর্ণ ফাইলের সাথে পার্টিয়াল না করে তুলনা করি,
  • এবং অনুসন্ধান প্যাটার্নের শেষ '$' হ'ল লাইনটির শেষের সাথে মেলে যাতে আপনি ডিরেক্টরি ম্যাচগুলি না পান, কেবলমাত্র পুরো ফাইল নাম প্যাচগুলি।

স্ট্যাটের সঠিক অবস্থান দরকার, তাই না? আমি সন্ধান করছি কারণ আমার কাছে কেবলমাত্র ফাইলের নামের একটি তালিকা রয়েছে এবং সেগুলি অসংখ্য ডিরেক্টরিতে থাকতে পারে। দুঃখিত যদি এটি পরিষ্কার না ছিল।
অ্যান্ড্রু স্ট্যাসি

হুম। ইয়া আপনি বলেননি যে আপনার কোনও পাথ ছাড়াই ফাইলের নাম ছিল! পরিবর্তে আপনি যে সমস্যাটি ঠিক করতে পারেন? এটি একই ডেটাসেট জুড়ে একগুচ্ছ সময় অনুসন্ধান চালানোর চেয়ে আরও কার্যকর efficient
কালেব

সম্পাদনার জন্য ধন্যবাদ, এবং নির্দিষ্ট না হওয়ার জন্য আবার দুঃখিত। ফাইলের নাম / পথটি আমি ঠিক করতে যাচ্ছি না - ফাইল দুটি সিস্টেমে বিভিন্ন জায়গায় থাকতে পারে তাই আমি এমন একটি সমাধান চাই যা তার চারপাশে কাজ করার পক্ষে যথেষ্ট শক্ত। কম্পিউটারটি আমার স্পেসিফিকেশনের সাথে কাজ করবে , অন্যভাবে নয়! গুরুতরভাবে, এটি আমি প্রায়শই করি না - আমি জায়গা তৈরি করতে কিছু পুরানো ফাইলগুলি মুছতে চাইছিলাম এবং সেগুলি আমার ব্যাকআপে রয়েছে তা নিশ্চিত করার জন্য কেবল "দ্রুত 'এন' নোংরা" উপায় চাইছিলাম।
অ্যান্ড্রু স্ট্যাসি

প্রথমে আপনাকে পুরো পাথের প্রয়োজন হবে না, আপনি যে ডিরেক্টরি নির্দেশিকাটি ব্যাক আপ করছেন তার কেবল একটি আপেক্ষিক পথ। আমাকে পরামর্শ দেওয়ার অনুমতি দিন যে যদি পথটি একই না হয় তবে ফাইলটি একরকম না হওয়ার ভাল সম্ভাবনা রয়েছে এবং আপনি নিজের পরীক্ষা থেকে মিথ্যা ইতিবাচক ফলাফল পেতে পারেন। দেখে মনে হচ্ছে আপনার সমাধানটি দ্রুততার চেয়ে আরও নোংরা হতে পারে; আপনার কিছু নেই যা ভেবে আমি আপনাকে জ্বলতে দেখতে চাই না। এছাড়াও, যদি ফাইলগুলি প্রথম স্থানে ব্যাকআপ দেওয়ার জন্য যথেষ্ট মূল্যবান হয় তবে আপনার প্রাথমিকগুলি মুছে ফেলা উচিত নয়, অন্যথায় আপনার ব্যাকআপগুলি ব্যাকআপ করা দরকার!
কালেব

AK! প্রশ্নটি কেন্দ্রীভূত করার চেষ্টা করার জন্য আমি বিশদ বিবরণ ছেড়ে দিয়েছি এবং আপনি সেগুলিকে অনেক অনুমানের সাথে পূরণ করছেন - যা আমার বলা উচিত - পুরোপুরি যুক্তিসঙ্গত তবে পুরোপুরি ভুল হতে পারে! এটি যথেষ্ট বলার অপেক্ষা রাখে না যে আমি জানি যে ফাইলটি যদি সেখানে থাকে এবং একটি নির্দিষ্ট ধরণের নাম সহ ডিরেক্টরিতে থাকে তবে আমি জানি যে এটি আসল ফাইল এবং এটি আমার মেশিনের অনুলিপি মুছে ফেলা নিরাপদ।
অ্যান্ড্রু স্ট্যাসি

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

মিল খুঁজে পেতে

  • pitfalls:
    • ফাইলনামগুলিতে নিউলাইনগুলি হ্যান্ডেল করা খুব শক্ত
    • ফাইল নামগুলিতে ফাঁকা এবং অনুরূপ জিনিসগুলিও খুব সুন্দর নয়। তবে যেহেতু ফাইলগুলির তালিকায় থাকা ফাইলগুলির উপর আপনার নিয়ন্ত্রণ রয়েছে, তবে সম্ভবত এই সমাধানটি ইতিমধ্যে যথেষ্ট ...
  • অপূর্ণতা:

    • যখন কোনও ফাইল সন্ধান করে, এটি অন্য একটি এবং অন্য একটি সন্ধানের জন্য দৌড়তে থাকে। আরও অনুসন্ধান এড়িয়ে ভাল লাগবে।
    • কিছু প্রস্তুতি সহ একবারে একাধিক ফাইল অনুসন্ধান করতে পারে:

      সন্ধান করুন-নাম 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 অনুসন্ধানের জন্য aa ফাইল foo.ba, বা oo.bar - --regexp-build এর সাথে মিলবে না (পি ছাড়া রেজেক্স দ্বারা বিভ্রান্ত হওয়া উচিত নয়)।

আপনি সনাক্ত করার জন্য একটি নির্দিষ্ট ডাটাবেস নির্দিষ্ট করতে পারেন এবং আপনার সর্বাধিক সাম্প্রতিক ফলাফলের প্রয়োজন হলে অনুসন্ধানের আগে আপনাকে এটি আপডেট করতে হবে।


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

এই উদাহরণটি ব্যাকআপ "* ~" ফাইলগুলি বাদ দেয় না এবং নিয়মিত ফাইল টাইপ "-টাইপ চ" এর সীমাবদ্ধ করে


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
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.