টি + বিড়াল: একটি আউটপুট বেশ কয়েকবার ব্যবহার করুন এবং তারপরে ফলাফলগুলি মিলিয়ে নিন


18

যদি আমি কিছু কমান্ড কল করি, উদাহরণস্বরূপ একটি echoআমি সেই কমান্ডের ফলাফলগুলি অন্য কয়েকটি কমান্ডের সাথে ব্যবহার করতে পারি tee। উদাহরণ:

echo "Hello world!" | tee >(command1) >(command2) >(command3)

বিড়ালের সাথে আমি বেশ কয়েকটি কমান্ডের ফলাফল সংগ্রহ করতে পারি। উদাহরণ:

cat <(command1) <(command2) <(command3)

আমি একই সাথে উভয় জিনিস করতে সক্ষম হতে চাই, যাতে আমি teeঅন্য কোনও কিছুর আউটপুটে এই আদেশগুলি কল করতে পারি (উদাহরণস্বরূপ echoআমি লিখেছি) এবং তারপরে তার ফলাফলগুলি একক আউটপুটে সংগ্রহ করতে পারি cat

এটা তোলে অনুক্রমে ফলাফল রাখা গুরুত্বপূর্ণ, এই উপায়ে আউটপুটে লাইন command1, command2এবং command3বিজড়িত করা উচিত না, কিন্তু আদেশ হিসাবে কমান্ড আছে (যেমন সঙ্গে ঘটে cat)।

এর চেয়ে ভাল বিকল্প হতে পারে catএবং teeএগুলি আমি এখনও অবধি জানি।

আমি অস্থায়ী ফাইলগুলি এড়াতে চাই কারণ ইনপুট এবং আউটপুটটির আকার বড় হতে পারে।

আমি এই কিভাবে করতে পারে?

পিডি: আরেকটি সমস্যা হ'ল এটি এমন একটি লুপে ঘটে যা অস্থায়ী ফাইলগুলি পরিচালনা করা আরও শক্ত করে তোলে। এটি আমার কাছে বর্তমান কোড এবং এটি ছোট টেস্টকেসের জন্য কাজ করে তবে অক্সফিল থেকে কোনওভাবে বুঝতে না পেরে এটি লেখার সময় এটি অসীম লুপ তৈরি করে।

somefunction()
{
  if [ $1 -eq 1 ]
  then
    echo "Hello world!"
  else
    somefunction $(( $1 - 1 )) > auxfile
    cat <(command1 < auxfile) \
        <(command2 < auxfile) \
        <(command3 < auxfile)
  fi
}

অক্সফাইলে পড়া এবং লেখাগুলি ওভারল্যাপিং বলে মনে হচ্ছে, যার ফলে সবকিছু বিস্ফোরিত হয়।


2
আমরা কত বড় কথা বলছি? আপনার প্রয়োজনীয়তা সমস্ত কিছু মেমরিতে রাখতে বাধ্য করে। কমান্ড 2 এবং কমান্ড 3 এমনকি প্রসেসিং শুরু করতে পারার আগে, কমান্ড 2 এবং কমান্ড 3 এমনকি প্রসেসিং শুরু করতে না পারার আগে, কমান্ড 1 প্রথমে সম্পূর্ণ করতে হবে (সুতরাং এটি সম্ভবত সম্পূর্ণ ইনপুটটি পড়ে এবং সম্পূর্ণ আউটপুট প্রিন্ট করে) (যদি না আপনি প্রথমে স্মৃতিতে তাদের আউটপুট সংগ্রহ করতে চান)।
frostschutz

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

4
আপনাকে অস্থায়ী ফাইলগুলি ব্যবহার করতে হবে; হয় ইনপুট echo HelloWorld > file; (command1<file;command2<file;command3<file)বা আউটপুট জন্য echo | tee cmd1 cmd2 cmd3; cat cmd1-output cmd2-output cmd3-output। এটি ঠিক কীভাবে এটি কাজ করে - সমস্ত কমান্ড সমান্তরালভাবে কাজ করে এবং প্রক্রিয়া করে তবেই টি ইনপুট কাঁটাচামচ করতে পারে। যদি একটি কমান্ড ঘুমায় (কারণ আপনি ইন্টারলিভিং চান না) এটি সহজেই সমস্ত কমান্ডগুলিকে ব্লক করে দেবে, যাতে ইনপুট দিয়ে স্মৃতি পূরণ করা রোধ করা যায় ...
frostschutz

উত্তর:


27

আপনি গনুহ stdbuf ও সংমিশ্রণ ব্যবহার করতে পারে peeথেকে moreutils :

echo "Hello world!" | stdbuf -o 1M pee cmd1 cmd2 cmd3 > output

প্রস্রাব popen(3)যারা 3 শেল কমান্ড লাইন গুলি এবং তারপর freadইনপুট s এবং fwriteএটি গুলি সব তিনটি, যা আপ 1M করতে বাফার করা হবে না।

ধারণাটি অন্তত ইনপুট হিসাবে বড় হিসাবে একটি বাফার করা উচিত। এই ভাবে তিনটি কমান্ড একই সাথে শুরু করা হলেও তারা কেবল pee pcloseতিনটি কমান্ড ক্রমিকভাবে ইনপুট আসতে দেখবে ।

প্রত্যেকটির উপর pclose, peeবাফারটি কমান্ডে ফ্লাশ করে এবং এটি সমাপ্তির জন্য অপেক্ষা করে। এটি গ্যারান্টি দেয় যে যতক্ষণ cmdxনা এই কমান্ডগুলি কোনও ইনপুট পাওয়ার আগে কিছু আউটপুট শুরু না করে (এবং তাদের পিতামাতার ফিরে আসার পরে আউটপুট চালিয়ে যেতে পারে এমন প্রক্রিয়াটি কাঁটাচামচ করবেন না), তিনটি কমান্ডের আউটপুট হবে না ইন্টারলিভড্।

বাস্তবে, এটি 3 টি কমান্ড একই সাথে শুরু হওয়া ত্রুটি সহ স্মৃতিতে একটি টেম্প ফাইল ব্যবহার করার মতো।

একই সাথে কমান্ডগুলি শুরু করা এড়াতে, আপনি peeশেল ফাংশন হিসাবে লিখতে পারেন :

pee() (
  input=$(cat; echo .)
  for i do
    printf %s "${input%.}" | eval "$i"
  done
)
echo "Hello world!" | pee cmd1 cmd2 cmd3 > out

তবে সাবধান থাকুন যে zshএনওএল অক্ষরের সাথে বাইনারি ইনপুট ব্যতীত অন্য শেলগুলি ব্যর্থ হবে।

এটি অস্থায়ী ফাইলগুলি ব্যবহার করা এড়িয়ে যায়, তবে এর অর্থ পুরো ইনপুট মেমরিতে সঞ্চয় করা থাকে।

যাই হোক না কেন, আপনাকে ইনপুটটি কোথাও, মেমোরিতে বা কোনও টেম্প ফাইলে সঞ্চয় করতে হবে।

প্রকৃতপক্ষে, এটি বেশ আকর্ষণীয় প্রশ্ন, কারণ এটি আমাদের একক কার্যক্রমে বেশ কয়েকটি সহজ সরঞ্জামকে সহযোগিতা করার ইউনিক্স ধারণার সীমা দেখায়।

এখানে, আমরা কাজটিতে বেশ কয়েকটি সরঞ্জাম সহযোগিতা করতে চাই:

  • উত্স কমান্ড (এখানে echo)
  • একটি প্রেরণকারী আদেশ ( tee)
  • কিছু ফিল্টার কমান্ড ( cmd1, cmd2, cmd3)
  • এবং একটি সমষ্টি কমান্ড ( cat)।

তারা সকলেই একই সাথে চলতে পারত এবং যে ডেটা পাওয়া যায় তার সাথে সাথে প্রক্রিয়া করার জন্য যে ডেটা বোঝায় তা তাদের কঠোর পরিশ্রম করতে পারলে ভাল লাগবে।

একটি ফিল্টার কমান্ডের ক্ষেত্রে এটি সহজ:

src | tee | cmd1 | cat

সমস্ত কমান্ড একই সাথে চালিত হয়, এটি উপলভ্য হওয়ার সাথে সাথে cmd1ডেটা গুটি করা শুরু করে src

তিনটি ফিল্টার কমান্ডের সাহায্যে আমরা এখনও একই কাজ করতে পারি: সেগুলি একযোগে শুরু করুন এবং পাইপগুলির সাথে তাদের সংযুক্ত করুন:

               ┏━━━┓▁▁▁▁▁▁▁▁▁▁┏━━━━┓▁▁▁▁▁▁▁▁▁▁┏━━━┓
               ┃   ┃░░░░2░░░░░┃cmd1┃░░░░░5░░░░┃   ┃
               ┃   ┃▔▔▔▔▔▔▔▔▔▔┗━━━━┛▔▔▔▔▔▔▔▔▔▔┃   ┃
┏━━━┓▁▁▁▁▁▁▁▁▁▁┃   ┃▁▁▁▁▁▁▁▁▁▁┏━━━━┓▁▁▁▁▁▁▁▁▁▁┃   ┃▁▁▁▁▁▁▁▁▁┏━━━┓
┃src┃░░░░1░░░░░┃tee┃░░░░3░░░░░┃cmd2┃░░░░░6░░░░┃cat┃░░░░░░░░░┃out┃
┗━━━┛▔▔▔▔▔▔▔▔▔▔┃   ┃▔▔▔▔▔▔▔▔▔▔┗━━━━┛▔▔▔▔▔▔▔▔▔▔┃   ┃▔▔▔▔▔▔▔▔▔┗━━━┛
               ┃   ┃▁▁▁▁▁▁▁▁▁▁┏━━━━┓▁▁▁▁▁▁▁▁▁▁┃   ┃
               ┃   ┃░░░░4░░░░░┃cmd3┃░░░░░7░░░░┃   ┃
               ┗━━━┛▔▔▔▔▔▔▔▔▔▔┗━━━━┛▔▔▔▔▔▔▔▔▔▔┗━━━┛

যা আমরা নামযুক্ত পাইপগুলির সাথে তুলনামূলকভাবে সহজেই করতে পারি :

pee() (
  mkfifo tee-cmd1 tee-cmd2 tee-cmd3 cmd1-cat cmd2-cat cmd3-cat
  { tee tee-cmd1 tee-cmd2 tee-cmd3 > /dev/null <&3 3<&- & } 3<&0
  eval "$1 < tee-cmd1 1<> cmd1-cat &"
  eval "$2 < tee-cmd2 1<> cmd2-cat &"
  eval "$3 < tee-cmd3 1<> cmd3-cat &"
  exec cat cmd1-cat cmd2-cat cmd3-cat
)
echo abc | pee 'tr a A' 'tr b B' 'tr c C'

(সর্বোপরি এই } 3<&0বিষয়টির চারপাশে কাজ করা হয় যে &থেকে পুনঃনির্দেশ stdinহয় /dev/null, এবং আমরা <>পাইপগুলি অপর প্রান্তটি অবধি অবরুদ্ধ হওয়া অবধি এড়িয়ে চলার জন্য ব্যবহার করি cat))

বা নামক পাইপগুলি এড়ানোর জন্য, কিছুটা বেশি বেদনাদায়কভাবে zshকপোক্রোক সহ:

pee() (
  n=0 ci= co= is=() os=()
  for cmd do
    eval "coproc $cmd $ci $co"

    exec {i}<&p {o}>&p
    is+=($i) os+=($o)
    eval i$n=$i o$n=$o
    ci+=" {i$n}<&-" co+=" {o$n}>&-"
    ((n++))
  done
  coproc :
  read -p
  eval tee /dev/fd/$^os $ci "> /dev/null &" exec cat /dev/fd/$^is $co
)
echo abc | pee 'tr a A' 'tr b B' 'tr c C'

এখন, প্রশ্নটি হল: একবার সমস্ত প্রোগ্রাম শুরু হয়ে সংযুক্ত হয়ে গেলে কি ডেটা প্রবাহিত হবে?

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

  • tee এর সমস্ত আউটপুট একই হারে ফিড দেয়, তাই এটি কেবল তার ধীর আউটপুট পাইপের হারে ডেটা প্রেরণ করতে পারে।
  • cat কেবলমাত্র দ্বিতীয় পাইপ (উপরের অঙ্কনের 6 টি পাইপ) থেকে পড়া শুরু হবে যখন সমস্ত ডেটা প্রথম (5) থেকে পড়েছে।

এর অর্থ হ'ল শেষ না হওয়া পর্যন্ত ডেটা পাইপ 6 এ প্রবাহিত হবে না cmd1। এবং, উপরেরটির মতো tr b Bএটিরও অর্থ এই হতে পারে যে ডেটা পাইপ 3 এ প্রবাহিত হবে না, যার অর্থ এটি 3, 3 বা 4 এর পাইপগুলির কোনওটিতে প্রবাহিত হবে না কারণ teeসমস্ত 3 এর সর্বনিম্ন হারে ফিড দেয়।

অনুশীলনে এই পাইপগুলির একটি নন-নাল আকার রয়েছে, তাই কিছু ডেটাগুলি পরিচালনা করার জন্য পরিচালনা করবে এবং আমার সিস্টেমে কমপক্ষে, আমি এটি পর্যন্ত কাজ করতে পারি:

yes abc | head -c $((2 * 65536 + 8192)) | pee 'tr a A' 'tr b B' 'tr c C' | uniq -c -c

এর বাইরেও, সাথে

yes abc | head -c $((2 * 65536 + 8192 + 1)) | pee 'tr a A' 'tr b B' 'tr c C' | uniq -c

আমরা একটি অচলাবস্থা পেয়েছি, যেখানে আমরা এই পরিস্থিতিতে আছি:

               ┏━━━┓▁▁▁▁2▁▁▁▁▁┏━━━━┓▁▁▁▁▁5▁▁▁▁┏━━━┓
               ┃   ┃░░░░░░░░░░┃cmd1┃░░░░░░░░░░┃   ┃
               ┃   ┃▔▔▔▔▔▔▔▔▔▔┗━━━━┛▔▔▔▔▔▔▔▔▔▔┃   ┃
┏━━━┓▁▁▁▁1▁▁▁▁▁┃   ┃▁▁▁▁3▁▁▁▁▁┏━━━━┓▁▁▁▁▁6▁▁▁▁┃   ┃▁▁▁▁▁▁▁▁▁┏━━━┓
┃src┃██████████┃tee┃██████████┃cmd2┃██████████┃cat┃░░░░░░░░░┃out┃
┗━━━┛▔▔▔▔▔▔▔▔▔▔┃   ┃▔▔▔▔▔▔▔▔▔▔┗━━━━┛▔▔▔▔▔▔▔▔▔▔┃   ┃▔▔▔▔▔▔▔▔▔┗━━━┛
               ┃   ┃▁▁▁▁4▁▁▁▁▁┏━━━━┓▁▁▁▁▁7▁▁▁▁┃   ┃
               ┃   ┃██████████┃cmd3┃██████████┃   ┃
               ┗━━━┛▔▔▔▔▔▔▔▔▔▔┗━━━━┛▔▔▔▔▔▔▔▔▔▔┗━━━┛

আমরা পাইপ 3 এবং 6 (প্রতিটি 64kiB) পূরণ করেছি। teeযে অতিরিক্ত বাইট পড়েছে, এটি এটি খাওয়ানো হয়েছে cmd1, কিন্তু

  • এটি cmd2খালি করার জন্য অপেক্ষা করায় এটি এখন পাইপ 3 এ লেখা অবরুদ্ধ
  • cmd2এটি খালি করতে পারে না কারণ এটি পাইপ on এ লেখা অবরুদ্ধ রয়েছে, catএটি খালি করার জন্য অপেক্ষা করছে
  • cat এটি খালি করতে পারে না কারণ এটি অপেক্ষা করছে যে পাইপ 5 এ আর কোনও ইনপুট নেই।
  • cmd1catআর কোনও ইনপুট নেই তা বলতে পারে না কারণ এটি থেকে আরও ইনপুটটির জন্য নিজেকে অপেক্ষা করছে tee
  • এবং কোনও ইনপুট নেই teeতা বলতে পারে না cmd1কারণ এটি ব্লক করা হয়েছে ... ইত্যাদি।

আমরা একটি নির্ভরতা লুপ পেয়েছি এবং এইভাবে একটি অচলাবস্থা রয়েছে।

এখন, সমাধান কি? বড় পাইপ 3 এবং 4 (এর সমস্ত srcআউটপুট ধারণ করতে যথেষ্ট বড় ) এটি করবে। উদাহরণস্বরূপ আমরা এর pv -qB 1Gমধ্যে সন্নিবেশ করে teeএবং cmd2/3যেখানে pv1G পর্যন্ত ডেটা অপেক্ষা করতে cmd2এবং cmd3সেগুলি পড়তে সঞ্চয় করতে পারি। এর অর্থ দুটি বিষয় হবে যদিও:

  1. এটি সম্ভবত মেমরির প্রচুর পরিমাণে ব্যবহার করছে এবং তদ্রূপ, এটি সদৃশ
  2. এটি সমস্ত 3 টি কমান্ড সহযোগিতা করতে ব্যর্থ হয়েছে কারণ cmd2বাস্তবে কেবলমাত্র যখন cmd1 শেষ হবে তখন ডেটা প্রক্রিয়াকরণ শুরু হবে।

দ্বিতীয় সমস্যার সমাধান হ'ল পাইপগুলি 6 এবং 7 টি আরও বড় করা। ধরে নিই cmd2এবং cmd3তারা যতটা আউটপুট খায়, তার বেশি স্মৃতি গ্রাহ্য হবে না।

ডেটাটিকে অনুলিপি করা এড়ানোর একমাত্র উপায় হ'ল প্রেরক নিজেই ডেটা ধরে রাখা বাস্তবায়ন করা, এটি তারতম্যকে teeদ্রুততম আউটপুটের হারে ফিড সরবরাহ করতে পারে (ফিড সরবরাহ করার জন্য ডেটা ধারণ করে) ধীরে ধীরে তাদের নিজস্ব গতিতে)। আসলেই তুচ্ছ নয়।

সুতরাং, শেষ পর্যন্ত, প্রোগ্রামিং ছাড়াই যুক্তিসঙ্গতভাবে আমরা সর্বোত্তমভাবে পেতে পারি সম্ভবত এটির মতো (জেডএস সিনট্যাক্স):

max_hold=1G
pee() (
  n=0 ci= co= is=() os=()
  for cmd do
    if ((n)); then
      eval "coproc pv -qB $max_hold $ci $co | $cmd $ci $co | pv -qB $max_hold $ci $co"
    else
      eval "coproc $cmd $ci $co"
    fi

    exec {i}<&p {o}>&p
    is+=($i) os+=($o)
    eval i$n=$i o$n=$o
    ci+=" {i$n}<&-" co+=" {o$n}>&-"
    ((n++))
  done
  coproc :
  read -p
  eval tee /dev/fd/$^os $ci "> /dev/null &" exec cat /dev/fd/$^is $co
)
yes abc | head -n 1000000 | pee 'tr a A' 'tr b B' 'tr c C' | uniq -c

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

6
+1 চমৎকার ASCII শিল্পের জন্য একটি অতিরিক্ত :-)
কর্ট ফেফেল

3

আপনি যা প্রস্তাব করেন তা কোনও বিদ্যমান কমান্ডের সাহায্যে সহজেই করা যায় না এবং যাইহোক এটি তেমন কোনও অর্থ দেয় না। পাইপ পুরো ধারণা ( |ইউনিক্স / লিনাক্স-এ) যে হয় (অধিকতম) লিখেছেন আউটপুট একটি মেমরি বাফার ভর্তি পর্যন্ত, এবং তারপর (অধিকতম) বাফার থেকে ডেটা পড়ার রান পর্যন্ত এটি খালি। অর্থাত্ , এবং একই সাথে চালান, এর মধ্যে কখনও কখনও "ফ্লাইটে" সীমিত পরিমাণের বেশি ডেটা থাকার প্রয়োজন হয় না। আপনি যদি একক আউটপুটে বেশ কয়েকটি ইনপুট সংযোগ করতে চান তবে পাঠকদের মধ্যে যদি কেউ একজনের পিছনে পিছনে থাকে তবে আপনি অন্যকে থামিয়ে দেন (তখন সমান্তরালে চলার অর্থ কী?) অথবা আপনি আউটপুটটি স্তব্ধ করে রেখেছেন যে ল্যাগগার্ডটি এখনও পড়েনি yet (তারপরে মধ্যবর্তী ফাইল না রাখার কী দরকার?)।cmd1 | cmd2cmd1cmd2cmd1cmd2 আরো জটিল.

আমার প্রায় 30 বছরের ইউনিক্স অভিজ্ঞতায় আমি এমন কোনও পরিস্থিতি মনে করতে পারি না যা এমন একাধিক আউটপুট পাইপের জন্য সত্যিই উপকৃত হত।

আপনি একাধিক আউটপুটগুলিকে আজ একটি স্ট্রিমের সাথে একত্রিত করতে পারেন, কেবল কোনও আন্তঃবাহিত উপায়ে নয় (কীভাবে আউটপুটগুলি cmd1এবং cmd2আন্তঃবাহিত হওয়া উচিত ? এক লাইনে? 10 বাইট লেখার পালা নিতে হবে? বিকল্প "অনুচ্ছেদ" কোনওভাবে সংজ্ঞায়িত করা হয়েছে? এবং যদি একটি ঠিক না করে তবে ' দীর্ঘদিন ধরে কিছু লিখবেন না? এগুলি হ্যান্ডেল করা জটিল)। এটা যেমন দ্বারা সম্পন্ন করা হয় (cmd1; cmd2; cmd3) | cmd4, প্রোগ্রাম cmd1, cmd2এবং cmd3একের পর এক চালান হয়, আউটপুট ইনপুট হিসাবে পাঠানো হয় cmd4


3

আপনার ওভারল্যাপিং সমস্যার জন্য, লিনাক্সে (এবং সাথে bashবা zshতার সাথে নয় তবে ksh93) আপনি এটি হিসাবে এটি করতে পারেন:

somefunction()
(
  if [ "$1" -eq 1 ]
  then
    echo "Hello world!"
  else
    exec 3> auxfile
    rm -f auxfile
    somefunction "$(($1 - 1))" >&3 auxfile 3>&-
    exec cat <(command1 < /dev/fd/3) \
             <(command2 < /dev/fd/3) \
             <(command3 < /dev/fd/3)
  fi
)

প্রতিটি পুনরাবৃত্তিতে একটি নতুন প্রক্রিয়া পাওয়ার (...)পরিবর্তে এর ব্যবহারটি নোট করুন {...}যাতে আমরা একটি নতুন এফডি 3 নতুনকে নির্দেশ করতে পারি auxfile< /dev/fd/3এখন মুছে ফেলা ফাইলটি অ্যাক্সেস করার কৌশল। এটা তোলে লিনাক্স যেখানে চেয়ে অন্যান্য সিস্টেমের কাজ করবে না < /dev/fd/3মত হয় dup2(3, 0)এবং তাই FD 0 ফাইলের শেষে কার্সার সঙ্গে লিখতে কেবল-মোডে খোলা হবে।

নেস্টেড কিছু কাজ করার জন্য কাঁটাচামচ এড়ানোর জন্য, আপনি এটি লিখতে পারেন:

somefunction()
{
  if [ "$1" -eq 1 ]
  then
    echo "Hello world!"
  else
    {
      rm -f auxfile
      somefunction "$(($1 - 1))" >&3 auxfile 3>&-
      exec cat <(command1 < /dev/fd/3) \
               <(command2 < /dev/fd/3) \
               <(command3 < /dev/fd/3)
    } 3> auxfile
  fi
}

শেলটি প্রতিটি পুনরাবৃত্তিতে এফডি 3 ব্যাক আপ করার যত্ন নেবে । আপনি যত তাড়াতাড়ি ফাইল বিবরণীর বাইরে চলে যেতে চাইবেন।

যদিও আপনি এটি এটি করার জন্য আরও দক্ষ হিসাবে খুঁজে পেয়েছেন:

somefunction() {
  if [ "$1" -eq 1 ]; then
    echo "Hello world!" > auxfile
  else
    somefunction "$(($1 - 1))"
    { rm -f auxfile
      cat <(command1 < /dev/fd/3) \
          <(command2 < /dev/fd/3) \
          <(command3 < /dev/fd/3) > auxfile
    } 3< auxfile
  fi
}
somefunction 12; cat auxfile

অর্থাৎ, পুনর্নির্দেশগুলিকে বাসা দেবে না।

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