বাশ: প্রক্রিয়া প্রতিস্থাপনে ত্রুটিগুলি কীভাবে প্রচার করবেন?


19

আমি চাই যখনই আমার শেল স্ক্রিপ্টগুলি ব্যর্থ হয় যখনই তাদের সাথে চালিত কোনও আদেশ ব্যর্থ হয়।

সাধারণত আমি এটি দিয়ে:

set -e
set -o pipefail

(সাধারণত আমিও যোগ করি set -u)

বিষয়টি হ'ল উপরের কোনওটি প্রক্রিয়া বিকল্পের সাথে কাজ করে না। এই কোডটি "ঠিক আছে" প্রিন্ট করে এবং রিটার্ন কোড = 0 দিয়ে প্রস্থান করে, যখন আমি এটি ব্যর্থ হতে চাই:

#!/bin/bash -e
set -o pipefail
cat <(false) <(echo ok)

"পাইপফেইল" সমতুল্য কিছু আছে তবে প্রক্রিয়া প্রতিস্থাপনের জন্য? কমান্ডের কাছে যাওয়ার অন্য কোনও উপায় হ'ল কমান্ডের আউটপুট যেমন ফাইল হিসাবে থাকে তবে যখনই কোনও প্রোগ্রাম ব্যর্থ হয় তখন ত্রুটি বাড়াতে পারে?

একজন দরিদ্র লোকের সমাধান সনাক্ত করতে হবে যে যদি এই কমান্ডগুলি স্ট্ডারকে লিখিত হয় (তবে কিছু কমান্ডগুলি স্ট্যান্ডারকে সুসংগঠিত পরিস্থিতিতে লিখিত হয়)।

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


নামযুক্ত পাইপগুলি মুছতে আপনার ত্রুটি আটকাতে হবে না। আসলে, এটি মোটেই ভাল উপায় নয়। বিবেচনা করুন mkfifo pipe; { rm pipe; cat <file; } >pipe। যে কমান্ড স্তব্ধ করা পর্যন্ত একটি পাঠক প্রর্দশিত pipeকারণ এটি শেল যা নেই open()তাই যত তাড়াতাড়ি উপর একটি পাঠক আছে যেমন pipeFS জন্য লিঙ্ক pipeহয় rm; 'd এবং তারপর catকপি যে নল জন্য শেল এর বর্ণনাকারী আউট infile। এবং যাইহোক, আপনি যদি কোনও প্রক্রিয়া সাব এর বাইরে একটি ত্রুটি প্রচার করতে চান: <( ! : || kill -2 "$$")
মাইকেসার্ভ

নামযুক্ত পাইপগুলি মুছে ফেলার টিপটির জন্য ধন্যবাদ। দুর্ভাগ্যক্রমে, $$প্রতিস্থাপনটি আমার পক্ষে কাজ করে না, যেহেতু কমান্ড প্রতিস্থাপন প্রক্রিয়া ব্যবহার করে এমন কমান্ড হিসাবে করা হয় না যা একটি "নন শেল" কোড (পাইথন) থেকে তৈরি কমান্ড পাইপলাইনের ভিতরে করা হয় process সম্ভবত আমার অজগরে সাবপ্রসেস তৈরি করা উচিত এবং সেগুলি প্রগ্রেটিকভাবে পাইপ করা উচিত।
juanleon

সুতরাং ব্যবহার kill -2 0
মাইক্রজার্ভ

দুর্ভাগ্যক্রমে "কিল -2 0" অজগরটিকে মেরে ফেলবে (সংকেত)। মাল্টিথ্রিড অ্যাপ্লিকেশনটির মধ্যে ব্যবসায়িক যুক্তি সম্পাদনের জন্য সংকেত হ্যান্ডলারগুলি লেখার বিষয়টি আমি প্রত্যাশা করছি না :-)
জুনালিয়ন

আপনি যদি সংকেতগুলি পরিচালনা করতে না চান তবে কেন আপনি সেগুলি গ্রহণের চেষ্টা করছেন? যাইহোক, আমি আশা করি নামকরণ করা পাইপগুলি শেষ পর্যন্ত সবচেয়ে সহজ সমাধান হবে, কেবলমাত্র যদি এটি সঠিকভাবে করা হয় তবে আপনার নিজের কাঠামো তৈরি করা এবং আপনার নিজস্ব পছন্দসই প্রেরণকারী স্থাপন করা প্রয়োজন। এই প্রতিবন্ধকতাটি অতিক্রম করুন এবং এটি সমস্ত একসাথে আসে।
মাইক্রজারভ

উত্তর:


6

উদাহরণস্বরূপ আপনি কেবল সেই সমস্যাটি নিয়েই কাজ করতে পারেন:

cat <(false || kill $$) <(echo ok)
other_command

SIGTERMদ্বিতীয় কমান্ড কার্যকর ( other_command) সম্পাদন করার আগে স্ক্রিপ্টের সাবশেল d হয় । echo okকমান্ড "মাঝে মাঝে" মৃত্যুদন্ড কার্যকর করা হয়: সমস্যা হলো প্রক্রিয়া বদল অ্যাসিঙ্ক্রোনাস হয়। কোন গ্যারান্টি নেই যে kill $$কমান্ড এক্সিকিউট করা হয় আগে বা পরেecho ok কমান্ড। এটি অপারেটিং সিস্টেমের সময় নির্ধারণের বিষয়।

এটির মতো একটি বাশ স্ক্রিপ্ট বিবেচনা করুন:

#!/bin/bash
set -e
set -o pipefail
cat <(echo pre) <(false || kill $$) <(echo post)
echo "you will never see this"

এই স্ক্রিপ্টের আউটপুট হতে পারে:

$ ./script
Terminated
$ echo $?
143           # it's 128 + 15 (signal number of SIGTERM)

বা:

$ ./script
Terminated
$ pre
post

$ echo $?
143

আপনি এটি চেষ্টা করতে পারেন এবং কয়েকটি চেষ্টা করার পরে, আপনি আউটপুটে দুটি পৃথক অর্ডার দেখতে পাবেন। অন্য দুটি echoকমান্ড ফাইল বর্ণনাকারীর কাছে লেখার আগে প্রথমটিতে স্ক্রিপ্টটি সমাপ্ত করা হয়েছিল । দ্বিতীয় ইন falseবা killকমান্ড সম্ভবত পর নির্ধারণ করা হয়েছিল echoকমান্ড।

বা আরও সুনির্দিষ্টভাবে বলতে গেলে: শেল প্রক্রিয়াতে সংকেত প্রেরণকারী utillity signal()এর সিস্টেম কলটি ইকো সিস্টেলগুলির চেয়ে পরে বা তার আগে বা পূর্ব নির্ধারিত ছিল ।killSIGTERMwrite()

তবে স্ক্রিপ্টটি বন্ধ হয়ে যায় এবং প্রস্থান কোডটি 0 নয় 0. সুতরাং আপনার সমস্যাটি সমাধান করা উচিত।

আর একটি সমাধান অবশ্যই এর জন্য নামযুক্ত পাইপ ব্যবহার করা use তবে এটি আপনার স্ক্রিপ্টের উপর নির্ভর করে যে নামী পাইপ বা উপরের কাজটি বাস্তবায়ন করা কতটা জটিল।

তথ্যসূত্র:


2

রেকর্ডের জন্য, এবং উত্তর এবং মন্তব্যগুলি ভাল এবং সহায়ক হলেও, আমি কিছুটা আলাদা বাস্তবায়ন শেষ করেছি (প্যারেন্ট প্রসেসে সংকেত পাওয়ার বিষয়ে আমার কিছু বিধিনিষেধ ছিল যা আমি প্রশ্নের মধ্যে উল্লেখ করি নি)

মূলত, আমি এই জাতীয় কিছু করা শেষ করেছি:

command <(subcomand 2>error_file && rm error_file) <(....) ...

তারপরে আমি ত্রুটি ফাইলটি চেক করি। যদি এটি বিদ্যমান থাকে তবে আমি জানি যে সাবকম্যান্ডটি ব্যর্থ হয়েছে (এবং ত্রুটি_ফায়ালের বিষয়বস্তু কার্যকর হতে পারে)। আমি মূলত চেয়েছিলাম এমন আরও ভার্বোজ এবং হ্যাকিশ, তবে ওয়ান-লাইনার ব্যাশ কমন্ডে নামযুক্ত পাইপ তৈরির চেয়ে কম জটিল।


আপনার জন্য যা কিছু কাজ করে তা সাধারণত সবচেয়ে ভাল উপায়। বিশেষ করে ফিরে এসে উত্তর দেওয়ার জন্য ধন্যবাদ - সেলফিগুলি আমার প্রিয়।
মাইকজার্ভ

2

এই উদাহরণটি দেখায় যে কীভাবে killএকসাথে ব্যবহার করতে হয় trap

#! /bin/bash
failure ()
{
  echo 'sub process failed' >&2
  exit 1
}
trap failure SIGUSR1
cat < <( false || kill -SIGUSR1 $$ )

কিন্তু killআপনার সাব প্রক্রিয়া থেকে পিতামাতার প্রক্রিয়াতে কোনও রিটার্ন কোডটি প্রেরণ করতে পারে না।


আমি গৃহীত উত্তর এই প্রকরণ মত
sehe

1

আপনি যেমন পসিক্স শেলটি প্রয়োগ করেন $PIPESTATUS/ $pipestatusসমর্থন করেন না ঠিক তেমনভাবে আপনি কমান্ডগুলির প্রস্থান স্থিতিটি পাইপের মাধ্যমে পাশ দিয়ে পাঠাতে পারবেন:

unset -v false_status echo_status
{ code=$(
    exec 3>&1 >&4 4>&-
    cat 3>&- <(false 3>&-; echo >&3 "false_status=$?") \
             <(echo ok 3>&-; echo >&3 "echo_status=$?")
);} 4>&1
cat_status=$?
eval "$code"
printf '%s_code=%d\n' cat   "$cat_status" \
                      false "$false_status" \
                      echo  "$echo_status"

যা দেয়:

ok
cat_code=0
false_code=1
echo_code=0

অথবা আপনি pipefailনিজের হাতে প্রক্রিয়া প্রতিস্থাপনটি ব্যবহার এবং প্রয়োগ করতে পারেন যেমন আপনি শেলগুলি সমর্থন করেন না যা এটি সমর্থন করে না:

set -o pipefail
{
  false <&5 5<&- | {
    echo OK <&5 5<&- | {
      cat /dev/fd/3 /dev/fd/4
    } 4<&0 <&5 5<&-
  } 3<&0
} 5<&0
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.