পাইপ, {তালিকা; } শুধুমাত্র কিছু প্রোগ্রামের সাথে কাজ করে


13

এই ধরনের অনির্দেশ্য আচরণের জন্য পাওয়ার ব্যবহারকারীদের কাছ থেকে ব্যাখ্যা দরকার:

ps -eF | { head -n 1;grep worker; }
UID        PID  PPID  C    SZ   RSS PSR STIME TTY          TIME CMD
root       441     2  0     0     0   2 paź15 ?       00:00:00 [kworker/2:1H]

সবকিছু ঠিক আছে যদিও

ls -la / | { head -n 1;grep sbin; }

কেবলমাত্র আউটপুট প্রদর্শন করে head

... আমি ভেবেছিলাম stdout 2>&1এবং আমার পক্ষে এটি অদ্ভুত, কোনও ব্যাখ্যা বা এটি কীভাবে পরিচালনা করতে হবে তার পরামর্শ দেয় না?


1
শেষেরটি সবকিছু মুদ্রণ করা উচিত। headএবং grepকিছুই না।
jordanm

হ্যাঁ তুমিই ঠিক. তবে এটির পরিবর্তে, এলএস-এল / না করার সময় কেন PS -eF কাজ করে?
ast

উত্তর:


9

আমি ব্যবহার করে কিছু তদন্ত করেছি straceএবং এটি পাইপলাইনের বাম দিকে প্রোগ্রামটি টার্মিনালটিতে যেভাবে লিখেছে তার কারণে এটি প্রদর্শিত হচ্ছে। যখন lsকমান্ড এক্সিকিউট করা হয় এটি একটি একক ডাটা সব লিখেছেন write()। এটি headস্টিডিনের সমস্ত গ্রহণের কারণ হয়।

অন্যদিকে psব্যাচগুলিতে ডেটা লিখে রাখে, সুতরাং কেবল প্রথমটি write()গ্রাস করে headএবং তারপরে এটি বিদ্যমান। পরে কলগুলি write()সদ্য প্রসারিত grepপ্রক্রিয়াতে যাবে।

এর অর্থ এই যে আপনি যে প্রক্রিয়াটির জন্য চেষ্টা করছেন grepসেটি প্রথমটি না ঘটলে এটি কার্যকর হবে না write(), যেহেতু grepসমস্ত ডেটা দেখতে পাওয়া যায় না (এটি প্রথম লাইন থেকে ডেটা বিয়োগের চেয়েও কম দেখায়)।

আমার সিস্টেমে পিড 1 এর জন্য গ্রেপ করার চেষ্টা করার একটি উদাহরণ এখানে রয়েছে:

$ ps -eF | { head -n2; }
UID        PID  PPID  C    SZ   RSS PSR STIME TTY          TIME CMD
root         1     0  0  1697  3768   2 Oct03 ?        00:00:03 /lib/systemd/systemd
$ ps -eF | grep '/lib/systemd/systemd$'
root         1     0  0  1697  3768   2 Oct03 ?        00:00:03 /lib/systemd/systemd
$ ps -eF | { head -n1; grep '/lib/systemd/systemd$'; }
UID        PID  PPID  C    SZ   RSS PSR STIME TTY          TIME CMD

আপনার ps -eFউদাহরণটি কেবল সুযোগেই কাজ করে।


মহান ও ব্যাপক expalnation অনেক ধন্যবাদ
AST

1
আসলে এটি একটি রেসের শর্ত বেশি। এটি ঠিক যে এটি একাধিক write()কল করা ধীর গতিতে । যদি headএটির read()কলটি করতে ধীর হয়ে থাকে (যেমন পাইপ বাফারটিতে সমস্ত ডেটা থাকে) তবে এটি উভয় lsএবং একইরকম আচরণ প্রদর্শন করবে ps
প্যাট্রিক

6

এটি গ্লিবিসি-তে বাফারিংয়ের কারণে ঘটে। lsআউটপুট ক্ষেত্রে একটি অভ্যন্তরীণ বাফার হয় এবং যেমন ঠিক পাস করা হয় head। এর জন্য ps -eF, আউটপুটটি বৃহত্তর এবং তাই একবার headসমাপ্ত হওয়ার পরে grep, নিম্নলিখিতগুলি আউটপুটটির অবশিষ্ট অংশগুলি (তবে সম্পূর্ণ নয়) পায় ps

আপনি পাইপের আন-বাফারিং দ্বারা এ থেকে মুক্তি পেতে পারেন - উদাহরণস্বরূপ sed -u(এটি নিশ্চিত নয় যে এটি জিএনইউ এক্সটেনশন নয়):

$ ls -al / | sed -u "#" | { head -n 1; grep bin; }
total 76
drwxr-xr-x   2 root root  4096 Oct  2 21:52 bin
drwxr-xr-x   2 root root  8192 Oct  3 01:54 sbin

4

যা ঘটছে তা হল head -n 11 টিরও বেশি লাইন। অনুকূল থ্রুপুটটির জন্য, মাথা বাইটের অংশগুলি পড়ে, তাই এটি একবারে 1024 বাইট পড়তে পারে এবং তারপরে প্রথম লাইন বিরতির জন্য সেই বাইটগুলি সন্ধান করতে পারে। যেহেতু লাইন ব্রেকটি 1024 বাইটের মাঝামাঝি সময়ে হতে পারে, তাই বাকী ডেটা হারিয়ে যায়। এটি পাইপের পিছনে রাখা যায় না। সুতরাং পরবর্তী প্রক্রিয়া যা কার্যকর করে কেবলমাত্র 1025 এবং বাইটগুলি পায়।

আপনার প্রথম কমান্ডটি সফল হতে পারে কারণ kworkerপ্রক্রিয়াটি সেই প্রথম অংশের পরে headপড়ে reads

এটি কাজ করার জন্য, headএকবারে 1 টি অক্ষর পড়তে হবে। তবে এটি অত্যন্ত ধীর, তাই এটি হয় না।
দক্ষতার সাথে এই জাতীয় কিছু করার একমাত্র উপায় হ'ল "মাথা" এবং "গ্রেপ" উভয়ই একক প্রক্রিয়া করা।

এখানে এটি করার 2 টি উপায়:

echo -e '1\n2\n3\n4\n5' | perl -ne 'print if $i++ == 0 || /4/'

অথবা

echo -e '1\n2\n3\n4\n5' | awk '{if (NR == 1 || /4/) print }'

আরও অনেক কিছু আছে ...


হ্যাঁ আমি এই কাজটি পরিচালনা করার জন্য 'অবাকের উপায়' জানি but তবে ভাবছিলাম কেন {তালিকার সাথে আচরণটি এতটাই অনাকাঙ্ক্ষিত; }। এটি কীভাবে কাজ করে তা স্পষ্ট করার জন্য ধন্যবাদ। আমি উপরের সমস্ত উত্তর দিয়ে মুগ্ধ
ast

2

আপনি যদি কেবল প্রথম লাইনটি চান তবে নিম্নলিখিত ধরণের কৌশলটি আউটপুট স্ট্রিমটি পড়তে দুটি পৃথক কমান্ড ব্যবহার করে বাফারিং সমস্যাগুলি এড়িয়ে চলে:

$ ps -eF   | { IFS= read -r x ; echo "$x" ; grep worker; }
$ ls -la / | { IFS= read -r x ; echo "$x" ; grep sbin; }

readবিল্ট-ইন করা হয় শেল এবং মাত্র আউটপুট এক লাইন ইনপুট একজন সমগ্র বাফার গ্রাস করে না, তাই ব্যবহার readপাতার নিম্নলিখিত কমান্ডের জন্য আউটপুট বাকি সব।

আপনি যদি দুটি উদাহরণ ব্যবহার করে আপনার উদাহরণ দ্বারা দেখানো বাফারিং সমস্যাগুলিকে বোঝাতে চান sleepতবে সময় সংক্রান্ত সমস্যাগুলি মুছে ফেলার জন্য এগুলিতে একটি যুক্ত করুন এবং ডান দিকের কমান্ডগুলির মধ্যে যে কোনও একটি পড়ার চেষ্টা করার আগে বাম দিকের কমান্ডটি তার সমস্ত আউটপুট তৈরি করতে দেয় allow এটা:

$ ps -eF   | { sleep 5 ; head -n 1 ; grep worker; }
$ ls -la / | { sleep 5 ; head -n 1 ; grep sbin; }

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

আউটপুট লাইনের সংখ্যা রয়েছে এমন কয়েকটি উদাহরণ ব্যবহার করে আপনি বাফারিং সমস্যাটি আরও স্পষ্ট দেখতে পাচ্ছেন যাতে কোন লাইনগুলি অনুপস্থিত রয়েছে তা আপনি বলতে পারেন:

$ ps -eF          | cat -n | { sleep 5 ; head -n 1 ; head ; }
$ ls -la /usr/bin | cat -n | { sleep 5 ; head -n 1 ; head ; }

বাফারিং সমস্যাটি দেখার একটি সহজ উপায় হ'ল এটি ব্যবহার করে seqযা সংখ্যার একটি তালিকা তৈরি করে। কোন সংখ্যাটি নিখোঁজ হয় তা আমরা সহজেই বলতে পারি:

$ seq 1 100000    | { sleep 5 ; head -n 1 ; head ; }
1

1861
1862
1863
1864
1865
1866
1867
1868
1869

আমার কৌতুক সমাধানটি প্রথম লাইনটি পড়তে এবং প্রতিধ্বনিত করতে শেল ব্যবহার করে এমনকি ঘুমের বিলম্বের সাথে যুক্ত হয়েও সঠিকভাবে কাজ করে:

$ seq 1 100000 | { sleep 5 ; IFS= read -r x ; echo "$x" ; head ; }
1
2
3
4
5
6
7
8
9
10
11

নীচে headবাফারিংয়ের সমস্যাগুলি দেখানোর জন্য একটি সম্পূর্ণ উদাহরণ দেওয়া হচ্ছে , headপ্রতিবার তার পাঁচটি লাইন তৈরি করার জন্য কীভাবে আউটপুটটির পুরো বাফারটি ব্যয় করে তা দেখানো হয় । headক্রমযুক্ত পরবর্তী কমান্ডের জন্য যে গ্রাস করা বাফারটি পাওয়া যায় না :

$ seq 1 100000 | { sleep 5 ; head -5 ; head -5 ; head -5 ; head -5 ; }
1
2
3
4
5

1861
1862
1863
1864
499
3500
3501
3502
3503
7
5138
5139
5140
5141

1861উপরের সংখ্যাটি দেখে , আমরা আউটপুট থেকে headগুনে বাফারটি ব্যবহার করে বাফারের আকারটি গণনা করতে পারি :seq11860

$ seq 1 1860 | wc -c
8193

আমরা দেখতে পাই যে headপাইপ আউটপুটটির সম্পূর্ণ 8 কেবি (8 * 1024 বাইট) একবারে এমনকি নিজের আউটপুটটির কয়েক লাইন উত্পাদন করতে পেরে বাফার করছে।

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