কেন "বাশ-এক্স" এই স্ক্রিপ্টটি ভেঙে দেয়?


13

আমার কাছে একটি স্ক্রিপ্ট রয়েছে যা কিছু কমান্ড কতক্ষণ চালায় তা পরিমাপ করে।

এটির জন্য "রিয়েল" timeকমান্ড দরকার, অর্থাত্ বাইনারি উদাহরণস্বরূপ /usr/bin/time(যেমন ব্যাশ-অন্তর্নির্মিত -fপতাকা থাকে না )।

নীচে, একটি সরলীকৃত স্ক্রিপ্ট যা ডিবাগ করা যেতে পারে:

#!/bin/bash

TIMESEC=$(echo blah | ( /usr/bin/time -f %e grep blah >/dev/null ) 2>&1 | awk -F. '{print $1}')

echo ABC--$TIMESEC--DEF

if [ "$TIMESEC" -eq 0 ] ; then
   echo "we are here!"
fi

"Test.sh" হিসাবে সংরক্ষণ করুন এবং সম্পাদন করুন:

$ bash test.sh
ABC--0--DEF
we are here!

সুতরাং এটি কাজ করে।

এখন, বাশ কমান্ড লাইনে "-x" যুক্ত করে এটি ডিবাগ করার চেষ্টা করা যাক:

$ bash -x test.sh
++ echo blah
++ awk -F. '{print $1}'
+ TIMESEC='++ /usr/bin/time -f %e grep blah
0'
+ echo ABC--++ /usr/bin/time -f %e grep blah 0--DEF
ABC--++ /usr/bin/time -f %e grep blah 0--DEF
+ '[' '++ /usr/bin/time -f %e grep blah
0' -eq 0 ']'
test.sh: line 10: [: ++ /usr/bin/time -f %e grep blah
0: integer expression expected

যখন আমরা "-x" ব্যবহার করি এবং এটি ব্যতীত সূক্ষ্মভাবে কাজ করি তখন কেন এই স্ক্রিপ্টটি ভেঙে যায়?


1
হেহ। এটির সাথে দেখতে দেখতে -x, $()কনস্ট্রাক্ট -xতার ফলাফলের মান হিসাবে আউটপুট অন্তর্ভুক্ত করছে। এটি "প্রত্যাশিত" আচরণ বা ত্রুটিযুক্ত কিনা তা জানেন না ... বা সম্ভবত এটি আউটপুট ()দিচ্ছে এটি ভিতরে থাকা সাবশেল -x
জেফ ওয়াই

একদিকে: সেট করা BASH_XTRACEFDআপনাকে set -xআউটপুটটিকে অন্য কোথাও পুনর্নির্দেশ করতে দেয় এটির সমস্যা কম।
চার্লস ডাফি

উত্তর:


21

সমস্যা এই লাইন:

TIMESEC=$(echo blah | ( /usr/bin/time -f %e grep blah >/dev/null ) 2>&1 | awk -F. '{print $1}')

যেখানে আপনি স্ট্যান্ডার্ড আউটপুটটির সাথে মেলে মান ত্রুটিটি পুনর্নির্দেশ করছেন। বাশ তার ট্রেস-বার্তাগুলি স্ট্যান্ডার্ড ত্রুটিতে লিখছে echoএবং বাশ প্রক্রিয়াতে সমস্ত শেল কনস্ট্রাক্টের সাথে এটি অন্তর্নির্মিত ব্যবহার করছে ।

আপনি যদি এটি কিছু পরিবর্তন

TIMESEC=$(echo blah | sh -c "( /usr/bin/time -f %e grep blah >/dev/null )" 2>&1 | awk -F. '{print $1}')

এটি সেই সমস্যাটি সমাধান করবে এবং সম্ভবত ট্রেসিং এবং কাজের মধ্যে একটি গ্রহণযোগ্য সমঝোতা হতে পারে:

++ awk -F. '{print $1}'
++ sh -c '( /usr/bin/time -f %e grep blah >/dev/null )'
++ echo blah
+ TIMESEC=0                 
+ echo ABC--0--DEF
ABC--0--DEF
+ '[' 0 -eq 0 ']'
+ echo 'we are here!'
we are here!

7

আপনি কেবল সাব-শেলও ফেলে দিতে পারেন। স্পষ্টতই এটি নেস্টেড শেল যা একে অপরকে বিরক্ত করে তোলে:

TIMESEC=$(
    echo blah |
    /usr/bin/time -f %e grep blah 2>&1 >/dev/null |
    awk -F. '{print $1}'
)

যদি তুমি করো:


...| ( subshell ) 2>pipe | ...

... আপনি পাইপলাইনের সেই অংশটিকে সাবস্কেলের হোস্টিংয়ের জন্য চালিত সাব-শেলটি দিয়ে শুরু করবেন । কারন শেল ছাড়াই সাব-শেলের এমনকি ডিবাগ আউটপুটটিকে পুনর্নির্দেশ করে (যেমন এটি আপনি যে কোনও ধরণের {যৌগিক কমান্ড ; } >redirectব্যবহার করতে পছন্দ করতে পারেন) তার যে পাইপলাইনের অংশটি আপনি মিশ্রণ প্রবাহগুলিকে সরিয়ে দেন। এটি পুনঃনির্দেশের আদেশের সাথে করতে হবে।

পরিবর্তে, আপনি যদি প্রথমে কেবলমাত্র गेজটি চেষ্টা করছেন সেই কমান্ডগুলির ত্রুটি আউটপুটটিকে পুনঃনির্দেশিত করে এবং হোস্ট শেলের আউটপুটটিকে স্ট্ডার করতে দেয়, আপনি একই সমস্যাটি শেষ করবেন না।

এবং তাই...


... | command 2>pipe 1>/dev/null | ...

... হোস্ট শেল তার স্টাডার লেখার জন্য নিখরচায় যেখানে এটি খুশি সেখানে কেবল কমান্ডগুলির আউটপুটটিকে পুনরায় নির্দেশিত করে যা এটি পাইপে কল করে।


bash -x time.sh
+++ echo blah
+++ /usr/bin/time -f %e grep blah
+++ awk -F. '{print $1}'
++ TIMESEC=0
++ echo ABC--0--DEF
ABC--0--DEF
++ '[' 0 -eq 0 ']'
++ echo 'we are here!'
we are here!

এই বিষয়টির জন্য ...


TIMESEC=$(
    echo blah |
    /usr/bin/time -f %e grep blah 2>&1 >/dev/null
)
printf %s\\n "ABC--${TIMESEC%%.*}--DEF"
if [ "${TIMESEC%%.*}" -eq 0 ] ; then
   echo "we are here!"
fi
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.