পাইপ থেকে পড়ার সময় কেন 'সেড কিউ' আলাদাভাবে কাজ করে?


25

আমি 'টেস্ট' নামে একটি পরীক্ষা ফাইল তৈরি করেছি যাতে নিম্নলিখিতটি রয়েছে:

xxx
yyy
zzz

আমি আদেশটি চালিয়েছি:

(sed '/y/ q'; echo aaa; cat) < test

এবং আমি পেয়েছি:

xxx
yyy
aaa
zzz

তারপরে আমি দৌড়েছি:

cat test | (sed '/y/ q'; echo aaa; cat)

এবং পেয়েছিলাম:

xxx
yyy
aaa

প্রশ্ন

sed'y' এর সাথে কোনও লাইনের মুখোমুখি হওয়া অবধি পড়া এবং মুদ্রণ করা, তারপরে থামে। প্রথম ক্ষেত্রে, তবে দ্বিতীয় নয়, বিড়াল বাকীটি পড়ে এবং মুদ্রণ করে।

আচরণের এই পার্থক্যের পিছনে কী ঘটতে পারে তা কেউ ব্যাখ্যা করতে পারেন?

আমি লক্ষ্য করেছি যে এটি উবুন্টু 16.04 এবং সেন্টোস 6 তে এইভাবে কাজ করে তবে সেন্টোস 7-তে কোনওটি 'zzz' প্রিন্ট করে না।


আমার অনুমান যে cat(সাব শেলের মধ্যে) প্রথম ক্ষেত্রে ফাইল ডেস্ক্রিপ্টর পুনরায় ব্যবহার করতে পারে, কারণ স্টিডিন একটি আসল ফাইলের সাথে আবদ্ধ। দ্বিতীয় ক্ষেত্রে, স্টিডিন একটি পাইপ থেকে এবং কোনও আসল ফাইল নয়। নোট যে (sed '/y/ q'; echo aaa; cat) < <(cat test)মুদ্রণ না zzz
মার্টিন নিল্ট

1
এর একটি সহজ উদাহরণ: (head -n1; head -n1) < testএবংcat test | (head -n1; head -n1)
মার্টিন নিল্ট

উত্তর:


22

যখন ইনপুট ফাইলটি সন্ধানযোগ্য (নিয়মিত ফাইল থেকে পড়ার মতো) বা অন-সন্ধানযোগ্য (পাইপ থেকে পড়ার মতো), sed(এবং অন্যান্য স্ট্যান্ডার্ড ইউটিলিটিস) আলাদাভাবে আচরণ করবে ( এই লিঙ্কটিরINPUT FILES বিভাগটি পড়ুন )।

দস্তাবেজের উদ্ধৃতি:

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

সুতরাং:

(sed '/y/ q'; echo aaa; cat) < test

sedqইওএফ পৌঁছানোর আগে ইউআইটি কমান্ড সম্পাদন করেছে , সুতরাং এটি zzzলাইনের শুরুতে ফাইলটি অফসেট ছেড়ে দিয়েছে , তাই catঅবশিষ্ট রেখাগুলি মুদ্রণ চালিয়ে যেতে পারে (জিএনইউ সেড কোনও অবস্থাতেই পসিক্স অনুগত নয়, নীচে দেখুন)।

এবং ডক থেকে অবিরত:

যে ফাইলগুলি অন্বেষণযোগ্য নয় তাদের ক্ষেত্রে সেই ফাইলের জন্য ওপেন ফাইলের বিবরণে অফসেট হওয়া ফাইলের অবস্থা নির্ধারিত

এই ক্ষেত্রে, আচরণটি অনির্ধারিত। সর্বাধিক মানক সরঞ্জামগুলি অন্তর্ভুক্ত sedযথাসম্ভব ইনপুট গ্রহণ করবে। এটি পড়তে হবে yyyলাইনটি পাস করুন , এবং qফাইলটি অফসেটটি পুনরুদ্ধার না করেই uit করা হবে, তাই কিছুই বাদ যায় না cat


জিএনইউ sedমানের সাথে সামঞ্জস্যপূর্ণ নয়, এটি সিস্টেমের স্টিডিও বাস্তবায়ন এবং গ্লিবসি সংস্করণের উপর নির্ভর করে:

$ (gsed '/y/ q'; echo aaa; cat) < test
xxx
yyy
aaa

এখানে, ফলাফলটি ম্যাক ওএসএক্স 10.11.6, ভার্চুয়াল মেশিনস সেন্টোস 7.2 - গ্লিবসি 2.17, উবুন্টু 14.04 - গ্লিবসি 2.19 থেকে পাওয়া গেছে, যা সিইপিএইচ ব্যাকএন্ডের সাথে ওপেনস্ট্যাকে চালিত হয়।

এই সিস্টেমে, আপনি -uস্ট্যান্ডার্ড আচরণ অর্জনের জন্য বিকল্পটি ব্যবহার করতে পারেন :

(gsed -u '/y/ q'; echo aaa; cat) </tmp/test

এবং পাইপ জন্য:

$ cat test | (gsed -u '/y/ q'; echo aaa; cat)
xxx
yyy
aaa
zzz

যা মারাত্মকভাবে অদক্ষ পারফরম্যান্সের দিকে পরিচালিত করে, কারণ sedএকবারে একটি বাইট পড়তে হয়। এর একটি আংশিক আউটপুট strace:

$ strace -fe read sh -c '{ sed -u "/y/q"; echo aaa; cat; } <test'
...
[pid  5248] read(3, "", 4096)           = 0
[pid  5248] read(0, "x", 1)             = 1
[pid  5248] read(0, "x", 1)             = 1
[pid  5248] read(0, "x", 1)             = 1
[pid  5248] read(0, "\n", 1)            = 1
xxx
[pid  5248] read(0, "y", 1)             = 1
[pid  5248] read(0, "y", 1)             = 1
[pid  5248] read(0, "y", 1)             = 1
[pid  5248] read(0, "\n", 1)            = 1
yyy
...

1
জিএনইউ- sedর ক্ষেত্রে এটি সিস্টেমের স্টডিও বাস্তবায়নের উপর নির্ভর করে। GNU সিস্টেমে (GNU libc সহ), GNU sedমেনে exit()চলবে যেহেতু stdio দ্বারা পরিচালিত ফাইলগুলির জন্য ফিরে চাইবে।
স্টাফেন চেজেলাস

@ স্টাফেনচেজেলাস: এটি যাচাই করবেন কীভাবে? sedআমার সেন্টোস .2.২ , উবুন্টু ১৪.০৪ ভিএম, অনুগত নয়, আমার মাঞ্জারো ল্যাপটপটি করেছে, সকলের একই sed সংস্করণ রয়েছে ৪.২.২
কিউংলম

@ স্টাফেনচেজেলাস: হুবহু হ'ল কিছু মনে হচ্ছে। আমার ভার্চুয়াল মেশিনে, strace -f sh -c '{ sed "/y/q"; echo aaa; cat; } <test'দেখান যে কোনও lseek()কাজ করা হয়নি, যখন আমার মাঞ্জারোতে lseek()আগে আগে ডাকা হয়েছিল exit_group()
cuonglm

আমি মনে করি এটি জিএনইউ লিবিসি-র সংস্করণে রয়েছে। আপনি একটি main() { char buf[999]; gets(buf); }'প্রোগ্রাম দিয়ে পরীক্ষা করতে পারেন ।
স্টাফেন চেজেলাস

1
@ স্টাফেনচাজেলাস: নিশ্চিত হয়েছে। আমার ভিএম উভয়েরই ২.১17 এবং ২.১৯ রয়েছে, যখন আমার মাঞ্জারোর একটি ২.২৩। এটি কি একটি গ্লাবসি বাগ বিবেচনা করা হয়? আপনার কি
গ্লিবিসি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.