কোনও পাইপ খালি আছে কিনা তা কীভাবে পরীক্ষা করবেন এবং তা না থাকলে ডেটাতে একটি কমান্ড চালান?


42

আমি বাশ স্ক্রিপ্টে একটি লাইন পাইপ করেছি এবং কোনও প্রোগ্রামে খাওয়ানোর আগে পাইপটিতে ডেটা আছে কিনা তা পরীক্ষা করতে চাই।

অনুসন্ধান করে আমি প্রায় খুঁজে পেয়েছি test -t 0কিন্তু এটি এখানে কাজ করে না। সর্বদা মিথ্যা প্রত্যাবর্তন। তাহলে কীভাবে নিশ্চিত হবেন যে পাইপের ডেটা রয়েছে?

উদাহরণ:

echo "string" | [ -t 0 ] && echo "empty" || echo "fill"

আউটপুট: fill

echo "string" | tail -n+2 | [ -t 0 ] && echo "empty" || echo "fill"

আউটপুট: fill

পূর্বোক্ত পাইপলাইন উত্পাদিত আউটপুট কিনা তা পরীক্ষা করার স্ট্যান্ডার্ড / ক্যানোনিকাল পদ্ধতি থেকে ভিন্ন ? প্রোগ্রামটিতে পাস করার জন্য ইনপুটটি সংরক্ষণ করা দরকার। এটি জেনারেলাইজ করে কিভাবে এক প্রক্রিয়া থেকে অন্য প্রক্রিয়াতে আউটপুট পাইপ করা যায় তবে প্রথমটির আউটপুট থাকে তবে কেবল কার্যকর করা যায়? যা ইমেল প্রেরণের উপর দৃষ্টি নিবদ্ধ করে।


উত্তর:


37

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

সুতরাং কেবল এটি করুন: একটি বাইট পড়ুন; আপনি যদি ফাইলের একটি শেষ সনাক্ত করেন, তবে ইনপুট ফাঁকা থাকার পরে আপনি যা করতে চান তা করুন; আপনি যদি বাইট পড়ে থাকেন তবে ইনপুটটি খালি না হলে আপনি কী করতে চান তা কাঁটাচামচ করুন, এতে বাইটযুক্ত পাইপ এবং বাকী ডেটা পাইপ করুন।

first_byte=$(dd bs=1 count=1 2>/dev/null | od -t o1 -A n | tr -dc 0-9)
if [ -z "$first_byte" ]; then
  # stuff to do if the input is empty
else
  {
    printf "\\$first_byte"
    cat
  } | {
    # stuff to do if the input is not empty
  }      
fi

ifneথেকে উপযোগ জোয়ি হেস এর moreutils কমান্ড সঞ্চালিত যদি তার ইনপুট ফাঁকা নয়। এটি সাধারণত ডিফল্টরূপে ইনস্টল করা হয় না তবে এটি বেশিরভাগ ইউনিক্স বৈকল্পিকের উপর সহজলভ্য বা সহজেই তৈরি করা উচিত। যদি ইনপুট ফাঁকা থাকে, ifneকিছুই করে না এবং 0 কে স্থিতি দেয় যা সফলভাবে চলমান কমান্ড থেকে আলাদা করা যায় না। ইনপুট ফাঁকা থাকলে আপনি যদি কিছু করতে চান তবে আপনার কমান্ডটি 0 না ফেরার ব্যবস্থা করতে হবে, যা সাফল্যের ক্ষেত্রে একটি পৃথক ত্রুটির স্থিতি ফিরে পাওয়ার মাধ্যমে করা যেতে পারে:

ifne sh -c 'do_stuff_with_input && exit 255'
case $? in
  0) echo empty;;
  255) echo success;;
  *) echo failure;;
esac

test -t 0এর সাথে কিছু করার নেই; এটি স্ট্যান্ডার্ড ইনপুটটি টার্মিনাল কিনা তা পরীক্ষা করে। এটি কোনও ইনপুট উপলব্ধ কিনা তা একভাবে বা অন্য কিছু বলে না।


স্ট্রিম ভিত্তিক পাইপ (সোলারিস এইচপি / ইউএক্স) সহ সিস্টেমগুলিতে, আমি বিশ্বাস করি যে আপনি পাইপটিতে কী ব্যবহার করছেন না তা দেখার জন্য আপনি I_PEEK ioctl ব্যবহার করতে পারেন।
স্টাফেন শেজেলাস

@ স্টাফেনচাজেলাস দুর্ভাগ্যক্রমে * বিএসডি-তে পাইপ / ফিফো থেকে ডেটা দেখার কোন উপায় নেই, সুতরাং কোনও পোর্টেবল peek ইউটিলিটি বাস্তবায়নের কোনও দৃষ্টিভঙ্গি নেই যা পাইপ থেকে প্রকৃত তথ্য ফিরিয়ে আনতে পারে, কেবলমাত্র তার কতটুকু নেই। (৪.৪ বিএসডি-তে, 386BSD ইত্যাদি পাইপগুলি সকেট পেয়ার হিসাবে প্রয়োগ করা হয়েছিল , তবে এটি বিএসডি-র পরবর্তী সংস্করণগুলিতে অন্তর্ভুক্ত ছিল - যদিও তারা তাদের দ্বি-দিকনির্দেশক রেখেছিল)।
মশবির

ব্যাশের একটি মাধ্যমে প্রকাশিত ইনপুট চেক করার একটি রুটিন রয়েছে read -t 0(এই ক্ষেত্রে টি মানে সময়সীমা, যদি আপনি অবাক হন)।
ইসহাক

11

একটি সহজ সমাধান হ'ল ifneকমান্ড ব্যবহার করা (যদি ইনপুট খালি না থাকে)। কিছু বিতরণে এটি ডিফল্টরূপে ইনস্টল করা হয় না। এটি moreutilsবেশিরভাগ ডিস্ট্রোজে প্যাকেজের একটি অংশ ।

ifne কেবলমাত্র যদি মান ইনপুট খালি না থাকে তবে একটি প্রদত্ত কমান্ড চালায় runs

দ্রষ্টব্য যে মানক ইনপুটটি খালি না ifneহলে এটি প্রদত্ত কমান্ডের মাধ্যমে প্রেরণ করা হবে


2
2017 হিসাবে, এটি ম্যাক বা উবুন্টুতে ডিফল্টরূপে নেই।
শ্রীধর সারনোবাত 3'17

7

পুরানো প্রশ্ন, তবে যদি কেউ আমার মতো করে আসে তবে: আমার সমাধান হ'ল সময়সীমা সহ পড়া।

while read -t 5 line; do
    echo "$line"
done

যদি stdinখালি থাকে তবে এটি 5 সেকেন্ড পরে ফিরে আসবে। অন্যথায় এটি সমস্ত ইনপুট পড়বে এবং আপনি প্রয়োজন হিসাবে এটি প্রক্রিয়া করতে পারেন।


যদিও আমি ধারণাটি পছন্দ করি, -tদুঃখজনকভাবে পসিক্সের
৯৯৯৯৯৯

6

stdin (0) এর ফাইল বর্ণনাকারী খোলা বা বন্ধ আছে কিনা তা পরীক্ষা করুন:

[ ! -t 0 ] && echo "stdin has data" || echo "stdin is empty"

আপনি যখন কিছু ডেটা পাস করেন এবং আপনি কিছু আছে কিনা তা পরীক্ষা করতে চান, আপনি যেভাবেই এফডি পাস করেন তাই এটিও ভাল পরীক্ষা নয়।
জাকুজে

1
[ -t 0 ]fd 0 টি টিটি টিতে খোলা আছে কিনা তা পরীক্ষা করে, এটি বন্ধ বা খোলা রয়েছে তা নয়।
মশবী

@ মোসভি আপনি কি দয়া করে এই বিষয়টি ব্যাখ্যা করতে পারেন যে কীভাবে কোনও স্ক্রিপ্টে সেই সমাধানটি ব্যবহার করে প্রভাব ফেলবে? এটি কাজ করে না যখন ক্ষেত্রে আছে?
জেপিজেড

@ জেপজেড হাহ? ./that_script </dev/null=> "স্টিডিনের ডেটা রয়েছে"। বা ./that_script <&-স্টিডিনকে সত্যিই বন্ধ করে দেওয়া
মশবির

5

আপনি test -s /dev/stdin(একটি স্পষ্টত সাবসেলের মধ্যে) পাশাপাশি ব্যবহার করতে পারেন ।

# test if a pipe is empty or not
echo "string" | 
    (test -s /dev/stdin && echo 'pipe has data' && cat || echo 'pipe is empty')

echo "string" | tail -n+2 | 
    (test -s /dev/stdin && echo 'pipe has data' && cat || echo 'pipe is empty')

: | (test -s /dev/stdin && echo 'pipe has data' && cat || echo 'pipe is empty')

8
আমার জন্য কাজ করে না। সর্বদা বলে পাইপ খালি আছে।
অ্যাম্ফটামাচাইন

2
আমার ম্যাকে কাজ করে তবে আমার লিনাক্স বাক্সে নয়।
শিখর

3

ব্যাশে:

read -t 0 

কোনও ইনপুটটিতে ডেটা রয়েছে কিনা তা সনাক্ত করে (কিছু না পড়ে)। তারপরে আপনি ইনপুটটি পড়তে পারেন (যদি পাঠটি কার্যকর হওয়ার সময় ইনপুট পাওয়া যায়):

if     read -t 0
then   read -r input
       echo "got input: $input"
else   echo "No data to read"
fi

দ্রষ্টব্য: বুঝতে পারি যে এটি সময় নির্ধারণের উপর নির্ভর করে। ইনপুটটিতে ইতিমধ্যে কেবল সময়ে read -tসঞ্চালনের সময় ডেটা রয়েছে কিনা তা সনাক্ত করে ।

উদাহরণস্বরূপ, সাথে

{ sleep 0.1; echo "abc"; } | read -t 0; echo "$?"

আউটপুটটি হ'ল 1(পঠন ব্যর্থতা, অর্থ: খালি ইনপুট)। প্রতিধ্বনি কিছু ডেটা লিখে তবে এটির প্রথম বাইটটি শুরু করা এবং লিখতে খুব দ্রুত নয়, সুতরাং, read -t 0রিপোর্ট করবে যে এর ইনপুটটি খালি, কারণ প্রোগ্রামটি এখনও কিছু লিখেনি।


github.com/bminor/bash/blob/… - এখানে বাশ কীভাবে ফাইল বর্ণনাকারীতে কিছু আবিষ্কার করে তা সনাক্ত করে of
পাভেল প্যাট্রিন

ধন্যবাদ @ পাভেলপাট্রিন
আইজাক

1
@ পাভেলপ্যাট্রিন যা কাজ করে না । আপনার লিঙ্কটি থেকে স্পষ্টভাবে দেখা গেছে, bashহয় একটি select()বা একটি করবে না ioctl(FIONREAD), বা উভয়ই করবে না, তবে এটি উভয়ই নয়, এটি কাজ করার জন্য to read -t0ভেঙ্গে গেছে. এটি ব্যবহার করবেন না
মশবির

ওহ, আজ আমি বুঝতে চেষ্টা করি এতে দু'ঘন্টা কী আছে? আপনাকে ধন্যবাদ, @ মমসি!
পাভেল প্যাট্রিন

3

ইউনিক্সে পড়ার জন্য ডেটা রয়েছে কি না তা যাচাই করার একটি সহজ উপায় হ'ল FIONREADআইওসিটিএল।

আমি কোনও স্ট্যান্ডার্ড ইউটিলিটি কেবল এটি করার কথা ভাবতে পারি না, সুতরাং এখানে এটি একটি তুচ্ছ প্রোগ্রাম রয়েছে ( ifneমোরটাল আইএমএইচও ;-) এর চেয়ে ভাল )।

fionread [ prog args ... ]

স্টিডিনে যদি কোনও ডেটা উপলভ্য না থাকে তবে এটি 1 স্ট্যাটাসের সাথে প্রস্থান করবে data যদি ডেটা থাকে তবে এটি চলবে prog। যদি কোনও progদেওয়া না হয় তবে এটি স্ট্যাটাস 0 দিয়ে প্রস্থান করবে।

আপনি pollযদি কেবল তাত্ক্ষণিকভাবে উপলব্ধ ডেটাতে আগ্রহী হন তবে আপনি কলটি সরাতে পারেন । এটি কেবল পাইপ নয়, বেশিরভাগ ধরণের এফডিএস নিয়ে কাজ করা উচিত।

fionread.c

#include <unistd.h>
#include <poll.h>
#include <sys/ioctl.h>
#ifdef __sun
#include <sys/filio.h>
#endif
#include <err.h>

int main(int ac, char **av){
        int r; struct pollfd pd = { 0, POLLIN };
        if(poll(&pd, 1, -1) < 0) err(1, "poll");
        if(ioctl(0, FIONREAD, &r)) err(1, "ioctl(FIONREAD)");
        if(!r) return 1;
        if(++av, --ac < 1) return 0;
        execvp(*av, av);
        err(1, "execvp %s", *av);
}

এই প্রোগ্রামটি আসলে কাজ করে? POLLHUPখালি কেসটি পরিচালনা করার জন্য আপনার কি কোনও ইভেন্টের জন্য অপেক্ষা করার দরকার নেই ? পাইপের অন্য প্রান্তে একাধিক ফাইলের বর্ণনা থাকলে তা কি কাজ করবে?
গিলস 19:37

হ্যাঁ এটা কাজ করে. পোলহপ কেবল পোলে ফিরে আসে, পলহাপের জন্য অপেক্ষা করার জন্য আপনার পলিন ব্যবহার করা উচিত। পাইপের যে কোনও প্রান্তে কতগুলি খোলা হ্যান্ডলগুলি তা বিবেচ্য নয়।
মশবী

পার্ল থেকে কীভাবে FIONREAD চালানো যায় তার জন্য unix.stackexchange.com/search?q=FIONREAD+ ব্যবহারকারীর33A22565 দেখুন (সংকলকগুলির তুলনায় আরও সাধারণভাবে উপলব্ধ)
স্টাফেন চ্যাজেলাস

রুটিন যে FIONREAD (বা HAVE_SELECT) ব্যবহার করে এখানে ব্যাশে প্রয়োগ করা হয়েছে
ইসহাক

2

আপনি যদি সংক্ষিপ্ত এবং রহস্যজনক ওয়ান-লাইনার পছন্দ করেন:

$ echo "string" | grep . && echo "fill" || echo "empty"
string
fill
$ echo "string" | tail -n+2 | grep . && echo "fill" || echo "empty"
empty

আমি মূল প্রশ্ন থেকে উদাহরণগুলি ব্যবহার করেছি। আপনি যদি -qগ্রাইপ সহ পাইপযুক্ত ডেটা ব্যবহারের বিকল্পটি না চান


0

আপনি পুরো প্রথম লাইনটি পড়ার ক্ষেত্রে যদি ঠিক থাকেন তবে এটি ব্যাশে একটি যুক্তিসঙ্গত ifne বাস্তবায়ন বলে মনে হচ্ছে

ifne () {
        read line || return 1
        (echo "$line"; cat) | eval "$@"
}


echo hi | ifne xargs echo hi =
cat /dev/null | ifne xargs echo should not echo

5
readইনপুটটি শূন্য থাকলেও এতে কোনও নতুনলাইন অক্ষর না থাকলে, মিথ্যাও প্রত্যাবর্তন করবে । যথেচ্ছ ডেটার জন্য ব্যবহার করা যাবে না। readIFS= read -r lineecho
স্টাফেন চেজেলাস

0

এটি আমার ব্যবহার করে কাজ করে read -rt 0

কোনও তথ্য ছাড়াই মূল প্রশ্ন থেকে উদাহরণ:

echo "string" | tail -n+2 | if read -rt 0 ; then echo has data ; else echo no data ; fi

না, এটি কাজ করে না। { sleep .1; echo yes; } | { read -rt0 || echo NO; cat; }(মিথ্যা নেতিবাচক) এবং true | { sleep .1; read -rt0 && echo YES; }(মিথ্যা ধনাত্মক) দিয়ে চেষ্টা করুন । বস্তুত, ব্যাশ এর readখোলা fds দ্বারা এমনকি বোকা বানানো হবে লেখ কেবল- মোড: { read -rt0 && echo YES; cat; } 0>/tmp/foo। একমাত্র জিনিসটি মনে হয় এটি হল select(2)এইচডি।
মোশি

... এবং selectকোনও এডিডিকে "প্রস্তুত" হিসাবে ফিরিয়ে দেবে যদি read(2)এটির উপর এটি অবরুদ্ধ না হয় তবে তা ফিরে আসবে EOFবা ত্রুটিযুক্ত হোক না কেন । উপসংহার: read -t0হয় ভাঙ্গা মধ্যে bash। এটি ব্যবহার করবেন না।
মোশি

@ মোসবি আপনি কি এটি ব্যাশব্যাগ দিয়ে রিপোর্ট করেছেন?
ইসহাক

@ মমসভি { sleep .1; echo yes; } | { read -rt0 || echo NO; cat; }এটি কোনও মিথ্যা নেতিবাচক নয় কারণ ( পাঠকটি কার্যকর করার সময়) কোনও ইনপুট নেই। পরবর্তীতে (ঘুম .1) যে ইনপুট হয় (বিড়াল জন্য) পাওয়া যায়।
ইসহাক

@ মমসভি কেন r বিকল্প সনাক্তকরণকে প্রভাবিত করে ?: echo "" | { read -t0 && echo YES; }হ্যাঁ মুদ্রণ echo "" | { read -rt0 && echo YES; }করে কিন্তু তা করে না।
ইসহাক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.