একটি বড় ফাইলের মাঝখানে পড়ুন


19

আমার কাছে 1 টিবি ফাইল রয়েছে। আমি বাইট 12345678901 থেকে 19876543212 বাইটে পড়তে চাই এবং এটি 100 এমবি র‌্যাম সহ একটি মেশিনে স্ট্যান্ডার্ড আউটপুটতে রেখে দিতে চাই।

আমি সহজেই পার্ল স্ক্রিপ্ট লিখতে পারি যা এটি করে। সিস্রেড 700 এমবি / সেকেন্ড সরবরাহ করে (যা ভাল) তবে সিস্রাইট কেবল 30 এমবি / গুলি সরবরাহ করে। আমি আরও দক্ষ কিছু চাই, প্রায়শই এমন কিছু যা প্রতিটি ইউনিক্স সিস্টেম ইনস্টল করা থাকে এবং এটি 1 জিবি / এস এর ক্রম সরবরাহ করতে পারে।

আমার প্রথম ধারণাটি হ'ল:

dd if=1tb skip=12345678901 bs=1 count=$((19876543212-12345678901))

তবে তা দক্ষ নয়।

সম্পাদনা:

কীভাবে আমি sswrit টি ভুল করেছিলাম তা আমার কোনও ধারণা নেই। এটি 3.5 গিগাবাইট / গুলি সরবরাহ করে:

perl -e 'sysseek(STDIN,shift,0) || die; $left = shift; \
         while($read = sysread(STDIN,$buf, ($left > 32768 ? 32768 : $left))){ \
            $left -= $read; syswrite(STDOUT,$buf);
         }' 12345678901 $((19876543212-12345678901)) < bigfile

এবং yes | dd bs=1024k count=10 | wcদুঃস্বপ্ন এড়ানো ।


আপনার কমান্ডbs=1M iflag=skip_bytes,count_bytes
frostschutz

উত্তর:


21

ছোট ব্লকের আকারের কারণে এটি ধীর। সাম্প্রতিক একটি জিএনইউ dd( কোর্টিলস ভি 8.16 + ) ব্যবহার করে, সহজ উপায় হ'ল বিকল্পগুলি skip_bytesএবং count_bytesবিকল্পগুলি ব্যবহার করা :

in_file=1tb

start=12345678901
end=19876543212
block_size=4096

copy_size=$(( $end - $start ))

dd if="$in_file" iflag=skip_bytes,count_bytes,fullblock bs="$block_size" \
  skip="$start" count="$copy_size"

হালনাগাদ

fullblock@ গিলস উত্তর অনুসারে বিকল্প যুক্ত করা হয়েছে । প্রথমে আমি ভেবেছিলাম এটি দ্বারা নিহিত হতে পারে count_bytes, তবে এটি তেমন নয়।

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


বিকল্পগুলি ও বিকল্পগুলি ddব্যতীত ব্যবহার করা আরও কঠিন:skip_bytescount_bytes

in_file=1tb

start=12345678901
end=19876543212
block_size=4096

copy_full_size=$(( $end - $start ))
copy1_size=$(( $block_size - ($start % $block_size) ))
copy2_start=$(( $start + $copy1_size ))
copy2_skip=$(( $copy2_start / $block_size ))
copy2_blocks=$(( ($end - $copy2_start) / $block_size ))
copy3_start=$(( ($copy2_skip + $copy2_blocks) * $block_size ))
copy3_size=$(( $end - $copy3_start ))

{
  dd if="$in_file" bs=1 skip="$start" count="$copy1_size"
  dd if="$in_file" bs="$block_size" skip="$copy2_skip" count="$copy2_blocks"
  dd if="$in_file" bs=1 skip="$copy3_start" count="$copy3_size"
}

আপনি বিভিন্ন ব্লক আকারের সাথেও পরীক্ষা করতে পারেন, তবে লাভগুলি খুব নাটকীয় হবে না। দেখুন - বিএস প্যারামিটারের ডিডি করার জন্য সর্বোত্তম মান নির্ধারণ করার কোনও উপায় আছে কি?


@ গ্রামীম দ্বিতীয় পদ্ধতিটি ব্যর্থ হবে যদি এর bsকারণ না হয় skip?
স্টিভেন পেনি

@ স্টিভেনপেনি, আপনি কী পাচ্ছেন তা নিশ্চিত নন, তবে skipএটি বাইট নয়, বেশ কয়েকটি ব্লক। হতে পারে আপনি বিভ্রান্ত যেহেতু skip_bytesপ্রথম উদাহরণ অর্থ ব্যবহার করা হয় skip হয় সেখানে বাইটে?
গ্রীম

তোমার bsহয় 4,096, যা বলতে চাচ্ছি যে আপনি আরো নিখুঁতভাবে লাফালাফি দিতে পারে না যে 4,096বাইট
স্টিভেন পেনি

1
@ স্টিভেনপেনি, এই কারণেই কোনও অনুলিপি প্রান্তিককরণ শুরু না করা বা শেষ না হওয়া ডেটা অনুলিপি করার জন্য ddপ্রথম এবং শেষটি ব্যবহার করে তিনটি আলাদা রান রয়েছে bs=1
গ্রিমে

6

bs=1ddএকবারে একটি বাইট পড়তে এবং লিখতে বলে । প্রতিটি readএবং writeকল জন্য একটি ওভারহেড আছে , যা এই ধীর করে তোলে। শালীন পারফরম্যান্সের জন্য একটি বৃহত ব্লকের আকার ব্যবহার করুন।

কমপক্ষে লিনাক্সের অধীনে আপনি যখন একটি সম্পূর্ণ ফাইল অনুলিপি করেন তখন আমি খুঁজে পেয়েছি cpএবং catএটির চেয়ে দ্রুততরdd , এমনকি আপনি যদি কোনও বৃহত ব্লকের আকার নির্দিষ্ট করে থাকেন।

একটি ফাইল একটি অংশ মাত্র কপি করার জন্য, আপনাকে নল করতে পারেন tailমধ্যে head। এর জন্য জিএনইউ কোর্টিলস বা অন্য কিছু বাস্তবায়ন প্রয়োজন যা head -cনির্দিষ্ট সংখ্যক বাইটের কপি করতে হয় ( tail -cপসিক্সে রয়েছে তবে head -cনেই)। লিনাক্সের একটি দ্রুত মানদণ্ড ddপাইপের কারণে এটি সম্ভবত ধীর হতে দেখায় ।

tail -c $((2345678901+1)) | head -c $((19876543212-2345678901))

সমস্যাটি ddহ'ল এটি নির্ভরযোগ্য নয়: এটি আংশিক ডেটা অনুলিপি করতে পারে । আমি যতদূর জানি, ddনিয়মিত ফাইলে পড়া এবং লেখার সময় নিরাপদ - দেখুন ডেডি অনুলিপি করার জন্য কখন ডিডি উপযুক্ত? (বা, কখন পড়বে () এবং লিখুন () আংশিক) - তবে কেবল যতক্ষণ এটি সংকেত দ্বারা বাধাগ্রস্ত হয় না । জিএনইউ কোর্টিলগুলি দিয়ে আপনি fullblockপতাকাটি ব্যবহার করতে পারেন তবে এটি পোর্টেবল নয়।

এর সাথে আর একটি সমস্যা ddহ'ল যে কাজ করে এমন একটি ব্লক গণনা খুঁজে পাওয়া শক্ত হতে পারে, কারণ স্কিপড বাইটের সংখ্যা এবং স্থানান্তরিত বাইট গণনা উভয়েরই ব্লকের আকারের একাধিক হওয়া প্রয়োজন। আপনি এখানে একাধিক কল ব্যবহার করতে পারেন dd: প্রথম আংশিক ব্লকটি অনুলিপি করার জন্য একটি, প্রান্তিকৃত ব্লকের বেশিরভাগ অংশ অনুলিপি করার জন্য এবং একটি শেষ আংশিক ব্লকটি অনুলিপি করার জন্য - শেলের স্নিপেটের জন্য গ্রিমের উত্তর দেখুন । তবে ভুলে যাবেন না যে আপনি যখন স্ক্রিপ্টটি চালাচ্ছেন, যদি না আপনি fullblockপতাকাটি ব্যবহার করেন তবে আপনাকে প্রার্থনা করতে ddহবে যা সমস্ত ডেটা অনুলিপি করবে। ddকোনও অনুলিপি আংশিক হলে একটি ননজারো স্থিতি ফেরত দেয়, তাই ত্রুটিটি সনাক্ত করা সহজ, তবে এটি মেরামতের কোনও কার্যকর উপায় নেই।

পসিক্সের শেল স্তরে আরও ভাল আর কিছু নেই has আমার পরামর্শটি হ'ল একটি বিশেষ বিশেষ উদ্দেশ্য সি প্রোগ্রাম লিখতে হবে (আপনি যা বাস্তবায়ন করেন তার উপর নির্ভর করে আপনি এটি কল করতে পারেন dd_done_rightবা tail_headবা mini-busybox)।


বাহ, yes | dd bs=1024k count=10 | wcসমস্যাটি আগে কখনও জানতাম না । কদর্য।
ওলে টেঞ্জ

4

সাথে dd:

dd if=1tb skip=12345678901 count=$((19876543212-12345678901)) bs=1M iflags=skip_bytes,count_bytes

বিকল্পভাবে এর সাথে losetup:

losetup --find --show --offset 12345678901 --sizelimit $((19876543212-12345678901))

এবং তারপরে dd, cat... লুপ ডিভাইস।


এটি খুব লিনাক্স কেন্দ্রিক বলে মনে হচ্ছে। এআইএক্স, ফ্রিবিএসডি, এবং সোলারিসেও কাজ করতে আমার একই কোডটি দরকার।
ওলে টাঞ্জ

0

এইভাবে আপনি এটি করতে পারেন:

   i=$(((t=19876543212)-(h=12345678901)))
   { dd count=0 skip=1 bs="$h"
     dd count="$((i/(b=64*1024)-1))" bs="$b"
     dd count=1 bs="$((i%b))"
   } <infile >outfile

আসলেই এটি প্রয়োজনীয় - এটির জন্য আরও বেশি কিছু লাগবে না। প্রথমেই dd count=0 skip=1 bs=$block_size1হবে lseek()কার্যত তাত্ক্ষণিকভাবে নিয়মিত ফাইল ইনপুট করে। কোনও মিসড ডেটা বা অন্যান্য মিথ্যাচারের বিষয়ে যা বলা আছে, তার কোনও সম্ভাবনা নেই , আপনি কেবল নিজের কাঙ্ক্ষিত শুরু অবস্থানটিতে সরাসরি চাইতে পারেন। ফাইল বিবরণকারীটির শেলটির মালিকানা রয়েছে এবং এটি ddকেবল এটির উত্তরাধিকার সূত্রে প্রাপ্ত, তাই তারা এর কার্সারের অবস্থানকে প্রভাবিত করবে এবং আপনি কেবল এটিকে পদক্ষেপে নিতে পারেন। এটি সত্যিই খুব সহজ - এবং কার্যকরের চেয়ে উপযুক্ত কোনও মানক সরঞ্জাম নেই dd

এটি একটি 64 কে ব্লকসাইজ ব্যবহার করে যা প্রায়শই আদর্শ। জনপ্রিয় বিশ্বাসের বিপরীতে, বৃহত্তর ব্লক আকারগুলি ddদ্রুত কাজ করে না । অন্যদিকে, ক্ষুদ্র বাফারগুলিও ভাল নয়। ddসিস্টেম কলগুলিতে তার সময়টি সিঙ্ক্রোনাইজ করা দরকার যাতে এটি মেমরিতে এবং আবারও অনুলিপি করে ডেটা অনুলিপি করার অপেক্ষা রাখে না, তবে এটি যাতে সিস্টেম কলগুলিতে অপেক্ষা না করে। সুতরাং আপনি এটি পর্যাপ্ত সময় নিতে চান যে পরেরটি read()শেষের জন্য অপেক্ষা করতে না পারে, তবে এত বেশি নয় যে আপনি প্রয়োজনীয়তার চেয়ে বড় আকারে বাফার করছেন।

সুতরাং প্রথম ddঅবস্থানে শুরু অবস্থান। শূন্য সময় লাগে । আপনি যে স্ট্যান্ডিন পড়তে সেই মুহুর্তে আপনার পছন্দ মতো অন্য কোনও প্রোগ্রাম কল করতে পারেন এবং এটি সরাসরি আপনার পছন্দসই বাইট অফসেটে পড়া শুরু করবে। আমি স্ট্যান্ডআউটে কাউন্ট ব্লকগুলি ddপড়তে অন্যকে কল করি ((interval / blocksize) -1)

সর্বশেষ যেটি প্রয়োজনীয় তা হ'ল পূর্ববর্তী বিভাগের ক্রিয়াকলাপের মডুলাস (যদি থাকে) অনুলিপি করা । এবং এটি।

এটি কোনওভাবেই বিশ্বাস করবেন না, যখন লোকেরা প্রমাণ ছাড়াই তাদের মুখে ঘটনা বর্ণনা করে। হ্যাঁ, ddএকটি সংক্ষিপ্ত পঠন করা সম্ভব (যদিও স্বাস্থ্যকর ব্লক ডিভাইস থেকে পড়ার সময় এই জাতীয় জিনিসগুলি সম্ভব নয় - এইভাবে নাম) । এই জাতীয় জিনিসগুলি কেবলমাত্র তখনই সম্ভব যদি আপনি ddকোনও ব্লক ডিভাইস বাদে অন্য পাঠানো স্ট্রিমটি সঠিকভাবে বাফার না করেন । উদাহরণ স্বরূপ:

cat data | dd bs="$num"    ### incorrect
cat data | dd ibs="$PIPE_MAX" obs="$buf_size"   ### correct

উভয় ক্ষেত্রেই সমস্ত ডেটা ddঅনুলিপি করে। প্রথম ক্ষেত্রে এটি সম্ভব (যদিও এর সাথে অসম্ভব ) যে কিছু আউটপুট ব্লক অনুলিপি করে যা কিছু অনুলিপি "$ num" বাইট হিসাবে সমান হবে কারণ যখন বাফারকে তার কমান্ডে নির্দিষ্টভাবে অনুরোধ করা হয় তখন কেবল কিছুতেই বাফার করা যায় spec লাইন। একটি প্রতিনিধিত্ব করে সর্বোচ্চ ব্লক-মাপ কারণ উদ্দেশ্য এর রিয়েল-টাইম I / O হয়।catddddbs=dd

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

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