মাথা অতিরিক্ত অক্ষর খায়


15

নিম্নলিখিত শেল কমান্ডটি কেবল ইনপুট স্ট্রিমের বিজোড় লাইনগুলি মুদ্রণ করবে বলে আশা করা হয়েছিল:

echo -e "aaa\nbbb\nccc\nddd\n" | (while true; do head -n 1; head -n 1 >/dev/null; done)

কিন্তু এর পরিবর্তে এটি শুধু প্রথম লাইন ছাপে: aaa

যখন এটি -c( --bytes) বিকল্পের সাথে ব্যবহৃত হয় তখন একই হয় না :

echo 12345678901234567890 | (while true; do head -c 5; head -c 5 >/dev/null; done)

1234512345প্রত্যাশা অনুযায়ী এই কমান্ড আউটপুট । তবে এটি কেবল ইউটিলিটির কোর্টিল বাস্তবায়নে কাজ করে head, Busybox বাস্তবায়ন এখনও অতিরিক্ত অক্ষর খায় তাই আউটপুট ঠিক হয় 12345

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

--bytesবিকল্পটি যখন ব্যবহৃত হয় তখন ক্ষেত্রে এটির জন্য একই কথা বলা যায় না । এক্ষেত্রে আপনি জানেন কত বাইট আপনার পড়া দরকার। সুতরাং আপনি ঠিক এই সংখ্যাটি বাইটগুলি পড়তে পারেন এবং এর চেয়ে বেশি নয়। Corelibs বাস্তবায়ন এই সুযোগ ব্যবহার করে, কিন্তু , busybox এক না হয়, তাহলে এখনও আরও বাইট চেয়ে একটি বাফার মধ্যে প্রয়োজনীয় সার্চ নেই। এটি সম্ভবত বাস্তবায়নকে সহজ করার জন্য করা হয়েছে।

তাই প্রশ্ন। headইনপুট স্ট্রিম থেকে জিজ্ঞাসা করা চেয়ে আরও বেশি অক্ষর গ্রাস করা কি ইউটিলিটির পক্ষে সঠিক ? ইউনিক্স ইউটিলিটিগুলির জন্য কি কোনও ধরণের স্ট্যান্ডার্ড রয়েছে? এবং যদি থাকে তবে এটি কি এই আচরণটি নির্দিষ্ট করে?

পুনশ্চ

Ctrl+Cউপরের কমান্ডগুলি বন্ধ করতে আপনাকে টিপতে হবে। ইউনিক্স ইউটিলিটিগুলি এর বাইরে পড়তে ব্যর্থ হয় না EOF। আপনি যদি টিপতে না চান তবে আপনি আরও জটিল কমান্ড ব্যবহার করতে পারেন:

echo 12345678901234567890 | (while true; do head -c 5; head -c 5 | [ `wc -c` -eq 0 ] && break >/dev/null; done)

যা আমি সরলতার জন্য ব্যবহার করি নি।


2
নিয়ারডুপ ইউনিক্স.স্ট্যাকেক্সেঞ্জাওয়েজ / সেকশনস / 48777/… এবং ইউনিক্স.স্ট্যাকেক্সেঞ্জাওয়েজ / প্রশ্নগুলি / ৮৪০১০/২ । এছাড়াও, যদি এই শিরোনামটি মুভিগুলিতে থাকত X তবে আমার উত্তরটি জারদোজ হবে :)
ডেভ_থমপসন_085

উত্তর:


30

ইনপুট স্ট্রিম থেকে জিজ্ঞাসা করা চেয়ে আরও বেশি অক্ষর গ্রাস করা মাথা ব্যবহারের পক্ষে কি সঠিক?

হ্যাঁ, এটি অনুমোদিত (নীচে দেখুন)।

ইউনিক্স ইউটিলিটিগুলির জন্য কি কোনও ধরণের স্ট্যান্ডার্ড রয়েছে?

হ্যাঁ, পসিক্স ভলিউম 3, শেল এবং ইউটিলিটিস

এবং যদি থাকে তবে এটি কি এই আচরণটি নির্দিষ্ট করে?

এটি তার পরিচিতিতে:

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

headএক মান ইউটিলিটি , তাই একটি POSIX-অনুসারী বাস্তবায়ন আচরণ উপরে বর্ণিত বাস্তবায়ন হয়েছে।

গনুহ head নেই সঠিক অবস্থান ফাইল বর্ণনাকারী ত্যাগ করার চেষ্টা, কিন্তু এটা পাইপ উপর চাইতে, তাই আপনার পরীক্ষার এটা অবস্থানে ফিরিয়ে আনতে ব্যর্থ হয় অসম্ভব। আপনি এটি ব্যবহার করে দেখতে পারেন strace:

$ echo -e "aaa\nbbb\nccc\nddd\n" | strace head -n 1
...
read(0, "aaa\nbbb\nccc\nddd\n\n", 8192) = 17
lseek(0, -13, SEEK_CUR)                 = -1 ESPIPE (Illegal seek)
...

readআয় 17 বাইট (সমস্ত উপলভ্য ইনপুট), headঐ চার প্রক্রিয়াকরণ এবং তারপর ফিরে 13 বাইট সরাতে চেষ্টা করে, কিন্তু এটি করতে পারেন না। (আপনি এখানেও দেখতে পারেন যে জিএনইউ headএকটি 8 কিবি বাফার ব্যবহার করে))

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

আপনি যদি কোনও ফাইলটিতে দস্তাবেজটি লিখেন এবং পরিবর্তে এটি ব্যবহার করেন তবে আপনি যে আচরণটি তার পরে পাবেন:

$ echo -e "aaa\nbbb\nccc\nddd\n" > file
$ < file (while true; do head -n 1; head -n 1 >/dev/null; done)
aaa
ccc

2
ব্যবহার করতে পারেন line(বর্তমানে POSIX / XPG থেকে সরানো কিন্তু এখনও অনেক সিস্টেমে উপলব্ধ) বা read( IFS= read -r line) যা একটি সময়ে এক বাইট পড়া সমস্যা এড়ানোর পরিবর্তে ইউটিলিটি।
স্টাফেন চেজেলাস

3
নোট করুন যে head -c 55 টি বাইট পড়বে বা একটি পূর্ণ বাফার বাস্তবায়নের উপর নির্ভর করবে (এটিও head -cমান নয় যে নোট করুন ), আপনি তার উপর নির্ভর করতে পারবেন না। আপনার dd bs=1 count=5কাছে গ্যারান্টি থাকা দরকার যে 5 বাইটের বেশি পড়বে না।
স্টাফেন চেজেলাস

ধন্যবাদ @ স্টাফেন, আমি -c 5বিবরণটি আপডেট করেছি ।
স্টিফেন কিট

মনে রাখবেন যে, headএর builtin ksh93সঙ্গে একটি সময়ে এক বাইট লেখা head -n 1যখন ইনপুট seekable নয়।
স্টাফেন চেজেলাস

1
@ অ্যান্টন_আরহ, ddকেবলমাত্র পাইপগুলির সাথে সঠিকভাবে কাজ করে bs=1যদি আপনি countপাইপগুলিতে পড়ার অনুরোধটি চেয়ে কম ফিরে আসতে পারেন (তবে কমপক্ষে একটি বাইট ইওফ পৌঁছে না দেওয়া পর্যন্ত)। GNU ddএর iflag=fullblockযে এটি উপশম করতে পারে।
স্টাফেন চেজেলাস

6

পসিক্স থেকে

মাথা উপযোগ মান আউটপুট তার ইনপুট ফাইল কপি হবে একটি মনোনীত সময়ে প্রতিটি ফাইলের জন্য আউটপুট শেষ হবে।

head ইনপুট থেকে কতটা পড়তে হবে সে সম্পর্কে এটি কিছু বলে না । এটি বাই-বাই-বাইট পড়ার দাবিটি নির্বোধ হবে, কারণ বেশিরভাগ ক্ষেত্রে এটি অত্যন্ত ধীর হবে।

তবে এটি readবিল্টিন / ইউটিলিটিতে সম্বোধন করা হয়েছে : readপাইপগুলি থেকে আমি সমস্ত শেলগুলি একবারে এক বাইট পাই এবং মানক পাঠ্যের অর্থ ব্যাখ্যা করা যায় যে এটি করা আবশ্যক, কেবলমাত্র একটি একক লাইনে পড়তে সক্ষম হতে:

পঠিত উপযোগ এক বা একাধিক শেল ভেরিয়েবল মধ্যে স্ট্যান্ডার্ড ইনপুট থেকে একটি একক যৌক্তিক লাইন পড়া যাবে।

ক্ষেত্রে read, যা শেল স্ক্রিপ্ট-এ ব্যবহার করা হয়, একটি সাধারণ ব্যবহারের ক্ষেত্রে ভালো কিছু হবে:

read someline
if something ; then 
    someprogram ...
fi

এখানে, এর স্ট্যান্ডার্ড ইনপুটটি someprogramশেলের মতোই তবে এটি প্রত্যাশা করা যেতে পারে যে someprogramএটি প্রথম ইনপুট লাইনটি খায় readএবং যা কিছু বাফার পরে পড়ে থাকবে তা নয়, যা পড়ে যায় read। অন্যদিকে, headআপনার উদাহরণ হিসাবে ব্যবহার করা অনেক বেশি অস্বাভাবিক।


আপনি যদি সত্যই প্রতিটি অন্যান্য লাইন মুছে ফেলতে চান তবে এমন কিছু সরঞ্জাম ব্যবহার করা ভাল and

$ seq 1 10 | sed -ne '1~2p'   # GNU sed
$ seq 1 10 | sed -e 'n;d'     # works in GNU sed and the BSD sed on macOS

$ seq 1 10 | awk 'NR % 2' 
$ seq 1 10 | perl -ne 'print if $. % 2'

তবে ভলিউম 3 এর পসিক্স পরিচয়ের "ইনপুট ফাইলস" বিভাগটি দেখুন ...
স্টিফেন কিট

1
পসিএক্স বলেছে: "যখন একটি স্ট্যান্ডার্ড ইউটিলিটি একটি সন্ধানযোগ্য ইনপুট ফাইলটি পড়ে এবং ফাইলের শেষের দিকে পৌঁছানোর আগে কোনও ত্রুটি ছাড়াই বন্ধ করে দেয়, ইউটিলিটি নিশ্চিত করবে যে ওপেন ফাইলের বিবরণে ফাইলটি অফসেটটি যথাযথভাবে ঠিক করা হয়েছে কেবলমাত্র শেষ বাইট দ্বারা প্রক্রিয়া করা হয়েছে ইউটিলিটি
seek

2
লক্ষ্য করুন, যদি না আপনি ব্যবহার -r, readএকাধিক লাইন পড়তে পারে (ছাড়া IFS=এটি নেতৃস্থানীয় এবং স্পেস এবং ট্যাব trailing (ডিফল্ট মান সঙ্গে স্ট্রিপ হবে $IFS))।
স্টাফেন চেজেলাস

@ অ্যালেক্সপি, হ্যাঁ, স্টিফেন ঠিক সেই অংশটি যুক্ত করেছেন।
ilkkachu

নোট করুন যে head এর builtin ksh93সঙ্গে একটি সময়ে এক বাইট লেখা head -n 1যখন ইনপুট seekable নয়।
স্টাফেন চেজেলাস

1
awk '{if (NR%2) == 1) print;}'

Hellóka :-) এবং সাইটে স্বাগতম! দ্রষ্টব্য, আমরা আরও বিস্তৃত উত্তর পছন্দ করি। এগুলি ভবিষ্যতের গুগলদের জন্য কার্যকর হওয়া উচিত।
পিটারহ - মনিকা 16
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.