পাইপে বাফারিং বন্ধ করুন


395

আমার কাছে একটি স্ক্রিপ্ট রয়েছে যা দুটি কমান্ডকে কল করে:

long_running_command | print_progress

long_running_commandকপি করে প্রিন্ট একটি উন্নতি কিন্তু আমি এটা অসন্তুষ্ট নই। আমি print_progressএটিকে আরও সুন্দর করতে ব্যবহার করছি (যথা, আমি একক লাইনে অগ্রগতিটি মুদ্রণ করি)।

সমস্যা: স্টাডাউটের সাথে একটি পাইপ সংযোগ একটি 4 কে বাফারকেও সক্রিয় করে, সুন্দর প্রিন্ট প্রোগ্রামে কিছুই পায় না ... কিছুই হয় না ... পুরোটা অনেক ... :)

আমি কীভাবে 4K বাফারটি অক্ষম করতে পারি long_running_command(না, আমার কাছে উত্স নেই)?


1
সুতরাং আপনি যখন লিংক ছাড়াই দীর্ঘ_সংস্থান_কম্যান্ড চালান আপনি অগ্রগতি আপডেটগুলি সঠিকভাবে দেখতে পাবেন, কিন্তু পাইপিং করার সময় সেগুলি বাফার হয়ে যায়?

1
হ্যাঁ, ঠিক তাই ঘটে।
অ্যারন ডিজুল্লা

20
বাফারিং নিয়ন্ত্রণের একটি সহজ পদ্ধতির অক্ষমতা কয়েক দশক ধরে একটি সমস্যা হয়ে দাঁড়িয়েছে। উদাহরণস্বরূপ, দেখুন: marc.info/?l=glibc-bug&m=98313957306297&w=4 যা মূলত বলেছে "আমাকে এই কাজটি করা যায় না এবং আমার অবস্থানকে ন্যায়সঙ্গত করতে এখানে কিছু তালি-ফাঁদ দেওয়া হয়েছে"


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

উত্তর:


254

আপনি unbufferকমান্ডটি (যা expectপ্যাকেজের অংশ হিসাবে আসে ) ব্যবহার করতে পারেন , যেমন

unbuffer long_running_command | print_progress

unbufferlong_running_commandসিউডোটারমিনাল (পিটিআই) এর মাধ্যমে সংযোগ স্থাপন করে , যা সিস্টেমটিকে এটি একটি ইন্টারেক্টিভ প্রক্রিয়া হিসাবে বিবেচনা করে, সুতরাং পাইপলাইনে 4-কিবি বাফারিং ব্যবহার না করে যা বিলম্বের সম্ভাব্য কারণ।

দীর্ঘ পাইপলাইনগুলির জন্য, আপনাকে প্রতিটি কমান্ড (চূড়ান্ত ব্যতীত) আনফার করতে হতে পারে, যেমন

unbuffer x | unbuffer -p y | z

3
আসলে, ইন্টারেক্টিভ প্রক্রিয়াগুলির সাথে সংযোগ স্থাপনের জন্য একটি পাইটির ব্যবহার সাধারণভাবে প্রত্যাশার সত্য।

15
পাইপলাইনে আনবফারকে কল করার সময় আপনার -p আর্গুমেন্টটি ব্যবহার করা উচিত যাতে স্টাডিন থেকে আনবুফার পড়তে পারে।

26
দ্রষ্টব্য: ডেবিয়ান সিস্টেমে, এই বলা হয় expect_unbufferএবং হয় expect-devনা প্যাকেজ expectপ্যাকেজ
bdonlan

4
@ বিডনলান: কমপক্ষে উবুন্টুতে (ডেবিয়ান-ভিত্তিক) expect-devউভয়ই সরবরাহ করে unbufferএবং expect_unbuffer(পূর্ববর্তীটি পরবর্তীকালে একটি প্রতীক) ink লিঙ্কগুলি expect 5.44.1.14-1(২০০৯) থেকে উপলব্ধ ।
jfs

1
দ্রষ্টব্য: উবুন্টু 14.04.x ​​সিস্টেমে এটি প্রত্যাশার-ডেভ প্যাকেজটিতেও রয়েছে।
আলেকজান্দ্রে মজেল

462

এই বিড়ালটির ত্বকের আরেকটি উপায় হ'ল stdbufপ্রোগ্রামটি ব্যবহার করা , যা জিএনইউ কোরিউটিলসের একটি অংশ (ফ্রিবিএসডি এর নিজস্ব একটিও রয়েছে)।

stdbuf -i0 -o0 -e0 command

এটি ইনপুট, আউটপুট এবং ত্রুটির জন্য সম্পূর্ণভাবে বাফারিং বন্ধ করে দেয়। কিছু অ্যাপ্লিকেশনের জন্য, লাইন বাফারিং কার্য সম্পাদনের কারণে আরও উপযুক্ত হতে পারে:

stdbuf -oL -eL command

দ্রষ্টব্য যে এটি কেবল গতিশীলভাবে সংযুক্ত অ্যাপ্লিকেশনগুলির জন্য stdioবাফারিং ( printf(), fputs()...) এর জন্য কাজ করে এবং কেবল যদি সেই অ্যাপ্লিকেশনটি অন্যথায় নিজের স্ট্যান্ডার্ড স্ট্রিমগুলির বাফারিং নিজে থেকে সামঞ্জস্য করে না, যদিও এটি বেশিরভাগ অ্যাপ্লিকেশনগুলিকে আবশ্যক।


6
"আনবফার" উবুন্টুতে ইনস্টল করা দরকার যা প্যাকেজের অভ্যন্তরে রয়েছে: প্রত্যাশা-দেব যা 2 এমবি ...
লেপ

2
এটি আনফার লগিংয়ের জন্য ডিফল্ট রাস্পিয়ান ইন্সটলে দুর্দান্ত কাজ করে। আমি sudo stdbuff … commandকাজ পেয়েছি যদিও stdbuff … sudo commandনা।
নাটভেদ

20
@qdii এর stdbufসাথে কাজ করে না tee, কারণ teeনির্ধারিত ডিফল্টগুলি ওভাররাইট করে stdbuf। এর ম্যানুয়াল পৃষ্ঠাটি দেখুন stdbuf
সিলিং

5
@ লেপ বিজারলি, আনফারটির x11 এবং tcl / tk এর উপর নির্ভরশীলতা রয়েছে যার অর্থ এটির প্রয়োজন> 80 এমবি আপনি যদি তাদের ব্যতীত কোনও সার্ভারে ইনস্টল করেন।
japtokal

10
@ কিডিআই তার নিজস্ব গতিশীল লোড লাইব্রেরি to োকাতে মেকানিজম stdbufব্যবহার LD_PRELOADকরে libstdbuf.so। এর অর্থ হ'ল এটি এই ধরণের এক্সিকিউটেবলের সাথে কাজ করবে না: সেটুইড বা ফাইল ক্ষমতা সেট সহ, স্ট্যাটিকালি লিঙ্কযুক্ত, স্ট্যান্ডার্ড লিবিসি ব্যবহার না করে। এই ক্ষেত্রে unbuffer/ script/ দিয়ে সমাধানগুলি ব্যবহার করা ভাল socatসেটআপড / ক্ষমতা সহ stdbuf দেখুন ।
পাবউক

75

এরপরে লাইন-বাফারিং আউটপুট মোডটি চালু করার আরেকটি উপায় long_running_commandহ'ল scriptআপনার long_running_commandসিউডো টার্মিনালে (পিটিআই) চালিত কমান্ডটি ব্যবহার করা ।

script -q /dev/null long_running_command | print_progress      # FreeBSD, Mac OS X
script -c "long_running_command" /dev/null | print_progress    # Linux

15
+1 দুর্দান্ত কৌশল, যেহেতু scriptএটি একটি পুরানো কমান্ড, এটি সমস্ত ইউনিক্সের মতো প্ল্যাটফর্মগুলিতে পাওয়া উচিত।
অ্যারোন দিগুল্লা

5
আপনার -qলিনাক্সেও দরকার :script -q -c 'long_running_command' /dev/null | print_progress
jfs

1
দেখে মনে হচ্ছে স্ক্রিপ্টটি পড়েছে stdin, যা long_running_commandঅন্তত ইন্টারেক্টিভ টার্মিনাল থেকে শুরু করার পরে পটভূমিতে এ জাতীয় চালানো অসম্ভব করে তোলে । কাজ করার জন্য, আমি স্টিডিন থেকে পুনর্নির্দেশ করতে সক্ষম হয়েছি /dev/null, যেহেতু আমার long_running_commandব্যবহার নেই stdin
হরিদসভ

1
এমনকি অ্যান্ড্রয়েডেও কাজ করে।
not2qubit

3
একটি উল্লেখযোগ্য অসুবিধা: ctrl-z আর কাজ করে না (যেমন আমি স্ক্রিপ্ট স্থগিত করতে পারি না)। এটি দ্বারা স্থির করা যেতে পারে, উদাহরণস্বরূপ: প্রতিধ্বনি | sudo স্ক্রিপ্ট -c / usr / স্থানীয় / বিন / ec2- স্ন্যাপশট-সমস্ত / দেব / নাল | ts, যদি আপনি প্রোগ্রামটির সাথে ইন্টারঅ্যাক্ট করতে সক্ষম না হন তবে আপত্তি করুন।
rlpowell

66

জন্য grep, sedএবং awkআপনি আউটপুটকে লাইন বাফার হতে বাধ্য করতে পারেন। তুমি ব্যবহার করতে পার:

grep --line-buffered

আউটপুটটিকে লাইন বাফার করতে বাধ্য করুন। ডিফল্টরূপে, আউটপুট লাইন বাফার হয় যখন স্ট্যান্ডার্ড আউটপুটটি টার্মিনাল হয় এবং অন্য ভিত্তিতে বাফার করে।

sed -u

আউটপুট লাইন বাফার করুন।

আরও তথ্যের জন্য এই পৃষ্ঠাটি দেখুন: http://www.perkin.org.uk/posts/how-to-fix-stdio-buffering.html


51

যদি আউটপুট কোনও টার্মিনালে না যায় যখন libc এর বাফারিং / ফ্লাশিং সংশোধন করতে সমস্যা হয়, আপনার স্যাটাট চেষ্টা করা উচিত । আপনি প্রায় কোনও ধরণের I / O প্রক্রিয়াটির মধ্যে দ্বিপাক্ষিক স্ট্রিম তৈরি করতে পারেন। এর মধ্যে একটি হ'ল একটি নকল প্রোগ্রাম যা একটি সিউডো টিটির সাথে কথা বলে।

 socat EXEC:long_running_command,pty,ctty STDIO 

এটা কি করে

  • একটি ছদ্ম tty তৈরি করুন
  • স্ট্রিন / স্টাডআউট হিসাবে pty এর স্লেভ পাশ দিয়ে কাঁটাচামচ দীর্ঘ_আপনি_কম্যান্ড
  • পিটিটির মাস্টার পাশ এবং দ্বিতীয় ঠিকানার মধ্যে দ্বিপাক্ষিক প্রবাহ স্থাপন করুন (এটি এটি এসটিডিওও)

যদি এটি আপনাকে একই আউটপুট দেয় long_running_commandতবে আপনি পাইপ দিয়ে চালিয়ে যেতে পারেন।

সম্পাদনা: বাহ আনফফার উত্তরটি দেখেনি! ঠিক আছে, সাকট যেভাবেই হোক দুর্দান্ত সরঞ্জাম, তাই আমি সম্ভবত এই উত্তরটি রেখে যেতে পারি


1
... এবং আমি স্যাম্যাট সম্পর্কে জানতাম না - দেখতে নেটকাটের মতো দেখতে অন্যরকম দেখাচ্ছে। ;) ধন্যবাদ এবং +1।

3
আমি socat -u exec:long_running_command,pty,end-close -এখানে ব্যবহার করব
স্টাফেন চ্যাজেলাস

20

তুমি ব্যবহার করতে পার

long_running_command 1>&2 |& print_progress

সমস্যাটি হ'ল libc স্ক্রিনে stdout করার সময় লাইন-বাফার এবং কোনও ফাইলের stdout করার সময় পূর্ণ-বাফার করবে। স্ট্যাডার এর জন্য কোনও বাফার নেই।

পাইপ বাফার নিয়ে সমস্যা হয় না বলে আমি মনে করি না, এটি সবই লাইবসির বাফার নীতি সম্পর্কে about


তুমি ঠিক বলছো; আমার প্রশ্ন এখনও আছে: পুনরায় সংশোধন না করে আমি কীভাবে লিবিসির বাফার নীতিতে প্রভাব ফেলতে পারি?
অ্যারন দিগুল্লা

@ স্টাফেনচাজেলা এফডি 1 স্টাডারে পুনঃনির্দেশিত হবে
ওয়াং হংকুইন

@ স্টাফেনচাজেলাস আমি আপনার যুক্তিযুক্ত বিষয়টি পাই না। plz একটি পরীক্ষা করুন, এটি কাজ করে
ওয়াং হংকুইন

3
ঠিক আছে, যা হচ্ছে তা হ'ল উভয়কেই zsh(যেখানে |&সিএসএস থেকে অভিযোজিত আসে) এবং bashযখন আপনি করেন cmd1 >&2 |& cmd2, এফডি 1 এবং 2 উভয়ই বাইরের স্টডআউটের সাথে সংযুক্ত থাকে। সুতরাং এটি বাইফার প্রতিরোধে কাজ করে যখন বাহ্যিক স্টডআউটটি টার্মিনাল হয় তবে কেবলমাত্র আউটপুটটি পাইপের মধ্য দিয়ে যায় না (তাই print_progressকিছুই প্রিন্ট করে না)। সুতরাং এটি একই long_running_command & print_progress(প্রিন্ট_প্রেস স্ট্রেড বাদে কোনও পাইপ যার কোনও লেখক নেই)। ls -l /proc/self/fd >&2 |& catতুলনায় আপনি যাচাই করতে পারেন ls -l /proc/self/fd |& cat
স্টাফেন চেজেলাস

3
আক্ষরিক |&জন্য এটি সংক্ষিপ্ত কারণ 2>&1 |। তাই cmd1 |& cmd2হয় cmd1 1>&2 2>&1 | cmd2। সুতরাং, এফডি 1 এবং 2 উভয়ই মূল স্টডারারের সাথে যুক্ত হয়েছে এবং পাইপে লেখার কিছুই নেই। ( s/outer stdout/outer stderr/gআমার আগের মন্তব্যে)
স্টাফেন চেজেলাস

11

এটি ক্ষেত্রে ব্যবহৃত হত, এবং সম্ভবত এখনও কেসটি হ'ল, যখন স্ট্যান্ডার্ড আউটপুটটি টার্মিনালে লেখা হয়, তখন এটি ডিফল্টরূপে লাইন বাফার হয় - যখন একটি নতুন লাইন লেখা হয় তখন লাইনটি টার্মিনালে লেখা হয়। যখন স্ট্যান্ডার্ড আউটপুটটি কোনও পাইপে প্রেরণ করা হয়, এটি সম্পূর্ণরূপে বাফার হয় - সুতরাং স্ট্যান্ডার্ড I / O বাফারটি পূরণ করা হলে তথ্য কেবল পাইপলাইনে পরবর্তী প্রক্রিয়ায় প্রেরণ করা হয়।

এটাই সমস্যার উত্স। প্রোগ্রামের লেখাকে পাইপে পরিবর্তন না করে এটিকে ঠিক করার জন্য আপনার অনেক কিছু করার আছে কিনা তা আমি নিশ্চিত নই। আপনি পতাকা setvbuf()সহ ফাংশনটি _IOLBFনিঃশর্তভাবে stdoutলাইন বাফার মোডে রাখতে ব্যবহার করতে পারেন । তবে কোনও প্রোগ্রামে এটি প্রয়োগের সহজ উপায় আমি দেখছি না। বা প্রোগ্রামটি fflush()উপযুক্ত পয়েন্টগুলিতে (আউটপুট প্রতিটি লাইন পরে) করতে পারে, কিন্তু একই মন্তব্য প্রযোজ্য।

আমি মনে করি আপনি যদি পাইপটি সিউডো-টার্মিনাল দিয়ে প্রতিস্থাপন করেন তবে মানক I / O গ্রন্থাগারটি আউটপুটটি টার্মিনাল বলে মনে করবে (কারণ এটি একধরণের টার্মিনাল) এবং স্বয়ংক্রিয়ভাবে বাফারে লাইন করে। যদিও বিষয়গুলির সাথে ডিল করার একটি জটিল উপায়।


7

আমি জানি এটি একটি পুরানো প্রশ্ন এবং এর ইতিমধ্যে প্রচুর উত্তর ছিল, তবে আপনি যদি বাফার সমস্যাটি এড়াতে চান তবে কেবল এর মতো কিছু চেষ্টা করুন:

stdbuf -oL tail -f /var/log/messages | tee -a /home/your_user_here/logs.txt

এটি বাস্তব সময়ে লগগুলিতে আউটপুট আসবে এবং এগুলি logs.txtফাইলে সংরক্ষণ করবে এবং বাফার আর tail -fকমান্ডকে প্রভাবিত করবে না ।


4
এটি দ্বিতীয় উত্তরের মতো দেখায়: - /
হারুন দিগুল্লা

2
stdbuf gnu কোরিউটিলে অন্তর্ভুক্ত করা হয়েছে (আমি সর্বশেষ সংস্করণ 8.25 এ যাচাই করেছি)। যাচাই করা এটি এম্বেডড লিনাক্সে কাজ করে।
zhaorufei

Stdbuf এর ডকুমেন্টেশন থেকে, NOTE: If COMMAND adjusts the buffering of its standard streams ('tee' does for example) then that will override corresponding changes by 'stdbuf'.
শ্রোমাউস

6

পাইপ নিয়ে সমস্যা আছে বলে আমি মনে করি না। দেখে মনে হচ্ছে আপনার দীর্ঘ চলমান প্রক্রিয়াটি তার নিজের বাফারকে ঘন ঘন পর্যাপ্তভাবে ফ্লাশ করছে না। পাইপের বাফার আকার পরিবর্তন করা এটির চারপাশের হ্যাক হতে পারে, তবে আমি মনে করি না কার্নেলটি পুনর্নির্মাণ না করে এটি সম্ভব হবে - এমন কিছু যা আপনি হ্যাক হিসাবে করতে চান না, কারণ এটি সম্ভবত অন্যান্য প্রক্রিয়াগুলিকে প্রভাবিত করে।


18
মূল কারণ হ'ল স্টাবডাউটি টিটিটি না হলে লাইবসি 4 কে বাফারিংয়ে স্যুইচ করে।
অ্যারন ডিজুল্লা

5
এটা খুব আকর্ষণীয়! কারণ পাইপ কোনও বাফারিং সৃষ্টি করে না। তারা বাফারিং সরবরাহ করে, তবে আপনি যদি পাইপ থেকে পড়েন তবে যা কিছু ডেটা উপলভ্য হবে তা পাইপটিতে আপনাকে বাফারের অপেক্ষা করতে হবে না। সুতরাং অপরাধীর আবেদনে স্টিডিও বাফারিং হবে।

3

এখানে এই পোস্ট অনুসারে , আপনি পাইপটি ইউলিমিটকে একক 512-বাইট ব্লকে হ্রাস করার চেষ্টা করতে পারেন। এটি অবশ্যই বাফারিং বন্ধ করবে না, তবে ভাল, 512 বাইট 4K: 3 এর চেয়ে কম


3

চাদের উত্তরের অনুরূপ শিরায় আপনি এইরকম একটি ছোট স্ক্রিপ্ট লিখতে পারেন:

# save as ~/bin/scriptee, or so
script -q /dev/null sh -c 'exec cat > /dev/null'

তারপরে scripteeপ্রতিস্থাপন হিসাবে এই কমান্ডটি ব্যবহার করুন tee

my-long-running-command | scriptee

হায়, আমি লিনাক্সে পুরোপুরি কাজ করার মতো সংস্করণ পাচ্ছি বলে মনে হয় না, তাই BSD- স্টাইলের ইউনিক্সগুলিতে সীমাবদ্ধ বলে মনে হয়।

লিনাক্স এ, এটি কাছে, তবে এটি শেষ হয়ে গেলে আপনি আপনার প্রম্পটটি ফিরে পাবেন না (যতক্ষণ না আপনি এন্টার চাপুন ইত্যাদি) ...

script -q -c 'cat > /proc/self/fd/1' /dev/null

কেন যে কাজ করে? "স্ক্রিপ্ট" বাফারিং বন্ধ করে দেয়?
অ্যারন দিগুল্লা

@ অ্যারন দিগুল্লা: scriptএকটি টার্মিনাল অনুকরণ করে, তাই হ্যাঁ, আমি বিশ্বাস করি এটি বাফারিং বন্ধ করে দেয়। এটি এতে প্রেরিত প্রতিটি চরিত্রের প্রতিধ্বনিও করে - এ কারণেই উদাহরণটিতে catপ্রেরণ করা /dev/nullহয়। যতদূর পর্যন্ত প্রোগ্রামটি চলমান রয়েছে script, এটি একটি ইন্টারেক্টিভ সেশনে কথা বলছে। আমি বিশ্বাস করি এটি এর সাথে একই রকম expectতবে scriptসম্ভবত এটি আপনার বেস সিস্টেমের একটি অংশ।
jwd

আমি যে কারণে ব্যবহার করছি teeতা হ'ল স্ট্রিমের অনুলিপি কোনও ফাইলে প্রেরণ করা। ফাইলটি কোথায় নির্দিষ্ট করা হবে scriptee?
ব্রুনো ব্রোনোস্কি

@ ব্রুনো ব্রোনোস্কি: আপনি ঠিক বলেছেন, এই প্রোগ্রামটির এটি একটি খারাপ নাম। এটি সত্যিই 'টি' অপারেশন করছে না। এটি আসল প্রশ্ন অনুযায়ী কেবল আউটপুট বাফারিং অক্ষম করছে। হতে পারে এটিকে "স্ক্রিপ্টকাট" বলা উচিত (যদিও এটি একচেটিয়াভাবে কাজ করছে না ...)। নির্বিশেষে, আপনি catকমান্ডটি প্রতিস্থাপন করতে পারেন tee myfile.txt, এবং আপনার পছন্দসই প্রভাবটি পাওয়া উচিত।
jwd

2

আমি এই চতুর সমাধানটি পেয়েছি: (echo -e "cmd 1\ncmd 2" && cat) | ./shell_executable

এই কৌশলটি করে। catঅতিরিক্ত ইনপুট (ইওএফ অবধি) পড়বে এবং echoএর আর্গুমেন্টের ইনপুট স্ট্রিমে রাখার পরে পাইপটিতে তা পাঠিয়ে দেবে shell_executable


2
আসলে, catএর আউটপুট দেখতে পাচ্ছে না echo; আপনি কেবল একটি সাবশেলে দুটি কমান্ড চালাবেন এবং উভয়ের আউটপুট পাইপে প্রেরণ করা হবে। সাবশেলের দ্বিতীয় কমান্ড ('বিড়াল') পিতামাতার / বাহ্যিক স্ট্ডিনের কাছ থেকে পড়ে, তাই এটি কাজ করে।
অ্যারন দিগুল্লা

0

মতে এই পাইপ বাফারের আকার কার্নেল সেট করা হতে বলে মনে হয় এবং আপনার কার্নেল পুনরায় কম্পাইল করতে পরিবর্তন করার প্রয়োজন হবে।


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