এখানে বেশ কয়েকটি বিষয় বিবেচনা করতে হবে।
i=`cat input`
ব্যয়বহুল হতে পারে এবং শাঁসের মধ্যে অনেকগুলি প্রকরণ রয়েছে।
এটি কমান্ড সাবস্টিটিউশন নামে পরিচিত feature ধারণাটি হ'ল কমান্ডের পুরো আউটপুটটি মাইনাসের পিছনে থাকা নতুন লাইনের অক্ষরগুলিকে iমেমরির ভেরিয়েবলের মধ্যে সঞ্চয় করা হবে।
এটি করার জন্য, শেলগুলি একটি সাবশেলে কমান্ডটি কাঁটাচামচ করে এবং পাইপ বা সকেটপায়ের মাধ্যমে তার আউটপুটটি পড়ে। আপনি এখানে প্রচুর প্রকরণ দেখতে পান। এখানে একটি 50MiB ফাইলে, আমি উদাহরণস্বরূপ ব্যাশটি দেখতে পাচ্ছি ksh93 এর চেয়ে 6 গুণ ধীর কিন্তু zsh এর চেয়ে সামান্য দ্রুত এবং দ্বিগুণ দ্রুত yash।
bashধীর হওয়ার মূল কারণ হ'ল এটি পাইপটি একবারে 128 বাইট থেকে পড়ে (অন্য শেলগুলি একবারে 4KiB বা 8KiB পড়ে) এবং সিস্টেম কল ওভারহেড দ্বারা দণ্ডিত হয়।
zshNUL বাইট (অন্যান্য শেলগুলি NUL বাইটে ভেঙে যায়) এড়াতে কিছু পোস্ট-প্রসেসিং করা yashদরকার এবং মাল্টি-বাইট অক্ষরগুলি বিশ্লেষণ করে আরও বেশি ভারী শুল্ক প্রক্রিয়াজাতকরণ করতে হবে।
সমস্ত শেলগুলিকে তারা আরও কম কম দক্ষতার সাথে চালিয়ে যাওয়া লেগেছে নতুন রৈখিক অক্ষরগুলি ফেলা করতে হবে।
কিছু অন্যের চেয়ে NU বাইটগুলি আরও কৃপণভাবে পরিচালনা করতে এবং তাদের উপস্থিতি পরীক্ষা করতে চাইতে পারে।
তারপরে আপনি যখন মেমরিতে বড় আকারের পরিবর্তনশীল হয়ে যান, তখন এটির যে কোনও হেরফেরটিতে সাধারণত আরও মেমরি বরাদ্দ করা এবং জুড়ে ডেটা জুড়ে দেওয়া অন্তর্ভুক্ত।
এখানে, আপনি ভেরিয়েবলের সামগ্রীটি (পাস করার ইচ্ছা করছিলেন) দিয়ে যাচ্ছেন echo।
ভাগ্যক্রমে, echoআপনার শেলের মধ্যে অন্তর্নির্মিত, অন্যথায় সম্পাদনা সম্ভবত একটি দীর্ঘ তালিকা ত্রুটির সাথে ব্যর্থ হত । তারপরেও, যুক্তি তালিকা অ্যারে তৈরি করা সম্ভবত ভেরিয়েবলের বিষয়বস্তু অনুলিপি করাতে জড়িত।
আপনার কমান্ড প্রতিস্থাপনের পদ্ধতির অন্য প্রধান সমস্যাটি হ'ল আপনি স্প্লিট + গ্লোব অপারেটরটি (ভেরিয়েবলটি উদ্ধৃত করে ভুলে গিয়ে) ডাকছেন ।
তার জন্য, শেলগুলি স্ট্রিংটিকে অক্ষরের একটি স্ট্রিং হিসাবে বিবেচনা করতে হবে (যদিও কিছু শেলগুলি সে ক্ষেত্রে বগি না করে) তবে ইউটিএফ -8 লোকেলগুলিতে, এর অর্থ ইউটিএফ -8 সিকোয়েন্সগুলি পার্সিং করা (যদি ইতিমধ্যে এর মতো না করা yashহয়) জন্য তাকান $IFSস্ট্রিং অক্ষর। যদি $IFSস্থান, ট্যাব বা নিউলাইন থাকে (যা পূর্বনির্ধারিত ক্ষেত্রে হয়), তবে অ্যালগোরিদম আরও জটিল এবং ব্যয়বহুল। তারপরে, এই বিভাজনের ফলে যে শব্দগুলি এসেছে তা বরাদ্দ এবং অনুলিপি করা দরকার।
গ্লোব অংশটি আরও ব্যয়বহুল হবে। তাহলে এই কথাগুলো কোন উল্লিখিত glob অক্ষর ( *, ?, [), তারপর শেল কিছু ডিরেক্টরি বিষয়বস্তু পড়তে এবং কিছু দামী প্যাটার্ন ম্যাচিং করতে হবে ( bashউদাহরণস্বরূপ এর বাস্তবায়ন কুখ্যাতিপূর্ণভাবে যে খুব খারাপ)।
যদি ইনপুটটিতে এমন কিছু থাকে তবে এটি /*/*/*/../../../*/*/*/../../../*/*/*অত্যন্ত ব্যয়বহুল হবে যার অর্থ হাজার হাজার ডিরেক্টরিকে তালিকাবদ্ধ করা এবং এটি কয়েকশ এমআইবিতে প্রসারিত হতে পারে।
তারপরে echoসাধারণত কিছু অতিরিক্ত প্রক্রিয়াজাতকরণ করা হবে। কিছু বাস্তবায়ন \xতার প্রাপ্ত আর্গুমেন্টের ক্রমগুলি প্রসারিত করে , যার অর্থ সামগ্রীটি বিশ্লেষণ করা এবং সম্ভবত অন্য একটি বরাদ্দ এবং ডেটা অনুলিপি করা।
অন্যদিকে, ঠিক আছে, বেশিরভাগ শেলগুলিতে catঅন্তর্নির্মিত হয় না, এর অর্থ একটি প্রক্রিয়া তৈরি করা এবং এটি চালানো (সুতরাং কোড এবং লাইব্রেরিগুলি লোড করা) তবে প্রথম অনুরোধের পরে, সেই কোড এবং ইনপুট ফাইলের সামগ্রী স্মরণে রাখা হবে। অন্যদিকে, কোনও মধ্যস্থতাকারী থাকবে না। catএকসাথে বড় পরিমাণে পড়বে এবং প্রসেসিং ছাড়াই সরাসরি লিখে ফেলবে এবং এটি বিপুল পরিমাণ মেমরি বরাদ্দ করার দরকার নেই, কেবলমাত্র এটির একটি বাফার এটি পুনরায় ব্যবহার করে।
এর অর্থ এটিও অনেক বেশি নির্ভরযোগ্য যেহেতু এটি NUL বাইটগুলিতে দম বন্ধ করে না এবং নতুন লাইনের চরিত্রগুলি ছাঁটাই করে না (এবং স্প্লিট + গ্লোব করে না, যদিও আপনি ভেরিয়েবলটি উদ্ধৃত করে এড়াতে পারবেন, এবং না আপনি যদি এর printfপরিবর্তে ব্যবহার করে এড়াতে পারেন তবে পালানোর ক্রমটি প্রসারিত করুন echo)
আপনি যদি এটিকে আরও অনুকূল করতে চান তবে catবেশ কয়েকবার আহ্বান না করে কেবল inputকয়েকবার পাস করুন cat।
yes input | head -n 100 | xargs cat
100 এর পরিবর্তে 3 টি কমান্ড চালাবে।
পরিবর্তনশীল সংস্করণটিকে আরও নির্ভরযোগ্য করে তুলতে আপনাকে ব্যবহার করতে হবে zsh(অন্যান্য শেলগুলি NUL বাইটগুলি সহ্য করতে পারে না) এবং এটি করতে হবে:
zmodload zsh/mapfile
var=$mapfile[input]
repeat 10 print -rn -- "$var"
আপনি যদি জানেন যে ইনপুটটিতে NUL বাইট নেই, তবে আপনি নির্ভরযোগ্যভাবে এটি পসিক্সলি করতে পারেন (যদিও এটি যেখানে বিল্টিন নেই সেখানে কাজ করবে printfনা):
i=$(cat input && echo .) || exit # add an extra .\n to avoid trimming newlines
i=${i%.} # remove that trailing dot (the \n was removed by cmdsubst)
n=10
while [ "$n" -gt 10 ]; do
printf %s "$i"
n=$((n - 1))
done
তবে এটি কখনই catলুপে ব্যবহারের চেয়ে বেশি দক্ষ হতে পারে না (যদি না ইনপুটটি খুব ছোট হয়)।
cat $(for i in $(seq 1 10); do echo "input"; done) >> output? :)