এটি কি ব্যাশে একটি বাগ? পাইপ থেকে ডাকলে `রিটার্ন` ফাংশনটি ছেড়ে দেয় না


16

ব্যাশ নিয়ে ইদানীং আমার কিছু অদ্ভুত সমস্যা হচ্ছে। আমার স্ক্রিপ্টটি সরল করার চেষ্টা করার সময় আমি এই ছোট্ট কোডের কোডটি নিয়ে এসেছি:

$ o(){ echo | while read -r; do return 0; done; echo $?;}; o
0
$ o(){ echo | while read -r; do return 1; done; echo $?;}; o
1

returnমুদ্রণ $?না করে ফাংশন থেকে বেরিয়ে আসা উচিত ছিল, তাই না? ঠিক আছে, তাহলে আমি পরীক্ষা করেছিলাম যে আমি কোনও পাইপ থেকে ফিরে আসতে পারি কিনা:

$ echo | while read -r; do return 1; done
bash: return: can only `return' from a function or sourced script

whileলুপ ছাড়াই একই ঘটে :

$ foo(){ : | return 1; echo "This should not be printed.";}
$ foo
This should not be printed.

আমি এখানে কি অনুপস্থিত কিছু আছে? একটি গুগল অনুসন্ধান এ সম্পর্কে কিছুই এনেছে! আমার বাশ সংস্করণটি 4.2.37 (1) - দেবিয়ান হুইজির উপর দয়া করে।


আমি আমার জবাবটিতে যে সেটিংসের প্রস্তাব দিয়েছি তাতে কিছু ভুল হয়েছে যা আপনার স্ক্রিপ্টটিকে আপনি যেটা প্রত্যাশা করেছেন তা স্বজ্ঞাতভাবে আচরণ করতে দেয়?
jlliagre

@ জেলিয়াগ্রে এটি হাজারো লাইনে একটি জটিল চিত্রনাট্য। অন্য কিছু ভাঙ্গার উদ্বেগের সাথে, আমি কেবল ফাংশনটির মধ্যে পাইপ চালানো এড়াতে পছন্দ করি, তাই আমি এটিকে একটি প্রক্রিয়া বিকল্পের সাথে প্রতিস্থাপন করেছি। ধন্যবাদ!
তেরেসা ই জুনিয়র

whileপ্রজননের জন্য প্রয়োজন না হলে কেন প্রথম দুটি উদাহরণ মুছে ফেলবেন না? এটি বিন্দু থেকে বিভ্রান্ত হয়।
মনিকার সাথে লাইটনেস রেস

@ লাইটনেসেসেসিনআরবিত whileএকটি পাইপের সাথে একটি লুপ একটি খুব সাধারণ ব্যবহার return। দ্বিতীয় উদাহরণটি আরও সোজা, তবে এটি এমন কিছু যা আমি বিশ্বাস করি না যে কেউ কখনও ব্যবহার করবে ...
টেরেসা ই জুনিয়র

1
দুর্ভাগ্যক্রমে আমার সঠিক উত্তর মুছে ফেলা হয়েছে ... আপনি অনির্ধারিত কিছু করার কারণে আপনি ধূসর অঞ্চলে রয়েছেন। আচরণটি নির্ভর করে যে শেলটি কীভাবে পাইপগুলিকে ব্যাখ্যা করে এবং এটি বর্ন শেল এবং কর্ন শেলের মধ্যে এমনকি আলাদা যদিও স্রোত উত্স থেকে প্রাপ্ত ছিল। বোর্ন শেল-এ, যখন লুপটি সাব-শেলের মধ্যে রয়েছে সুতরাং আপনি ইশাকে বাশের মতো দেখতে পাচ্ছেন, যখন Ksh-এ লুপটি অগ্রভূমি প্রক্রিয়া এবং এইভাবে ksh আপনার উদাহরণ সহ প্রতিধ্বনি কল করে না।
সুদৃ .়ভাবে

উত্তর:


10

সম্পর্কিত: /programming//a/7804208/4937930

এটি কোনও ত্রুটি নয় যা আপনি কোনও স্ক্রিপ্ট থেকে প্রস্থান করতে পারবেন না বা কোনও ফাংশন থেকে সাব-শেলের মাধ্যমে exitবা ফিরে আসতে পারবেন না return। এগুলি অন্য প্রক্রিয়াতে কার্যকর করা হয় এবং মূল প্রক্রিয়াটিকে প্রভাবিত করে না।

তদতিরিক্ত, আমি মনে করি আপনি বাশ (সম্ভবত) অপরিজ্ঞাত বিবরণে অনাবন্ধিত আচরণ দেখছেন। কোনও ফাংশনে, returnসাব-শেল কমান্ডগুলির শীর্ষ স্তরে কোনও ত্রুটি যুক্ত করা হয় না এবং এটি ঠিক এর মতো আচরণ করে exit

আইএমএইচও এটি returnমূল বিবৃতিটি কোনও ফাংশনে রয়েছে কি না তার উপর নির্ভর করে অসঙ্গত আচরণের জন্য এটি একটি ব্যাশ বাগ ।

#!/bin/bash

o() {
    # Runtime error, but no errors are asserted,
    # each $? is set to the return code.
    echo | return 10
    echo $?
    (return 11)
    echo $?

    # Valid, each $? is set to the exit code.
    echo | exit 12
    echo $?
    (exit 13)
    echo $?
}
o

# Runtime errors are asserted, each $? is set to 1.
echo | return 20
echo $?
(return 21)
echo $?

# Valid, each $? is set to the exit code.
echo | exit 22
echo $?
(exit 23)
echo $?

আউটপুট:

$ bash script.sh 
10
11
12
13
script.sh: line 20: return: can only `return' from a function or sourced script
1
script.sh: line 22: return: can only `return' from a function or sourced script
1
22
23

ত্রুটিপূর্ণ ভার্বোসটির অভাব অনির্ধারিত হতে পারে। তবে সত্য যে returnসাবসেলের শীর্ষ স্তরের কমান্ড সিকোয়েন্স থেকে কাজ করে না এবং বিশেষত সাব-শেল থেকে প্রস্থান করে না, বিদ্যমান নথিগুলি ইতিমধ্যে আমার প্রত্যাশা তৈরি করেছে। ওপি exit 1 || return 1যেখানে তারা ব্যবহার করার চেষ্টা করছে সেখানে ব্যবহার করতে পারে returnএবং তারপরে প্রত্যাশিত আচরণ পাওয়া উচিত। সম্পাদনা: @ হার্বার্ট এর উত্তর ইঙ্গিত করে যে toplevel returnsubshell হিসেবে কাজ হয় exit(কিন্তু শুধুমাত্র subshell থেকে)।
dubiousjim

1
@ সন্দেহজনক জিম আমার স্ক্রিপ্ট আপডেট করেছে। আমি বলতে চাইছি returnএকটি সহজ সাবসেল ক্রমটি কোনও ক্ষেত্রে রানটাইম ত্রুটি হিসাবে দৃserted় হওয়া উচিত , তবে বাস্তবে এটি কোনও ফুকনেশনে ঘটে না। এই সমস্যাটি gnu.bash.bug- এও আলোচনা করা হয়েছে , তবে এর কোন সিদ্ধান্ত নেই।
ইয়াগশী

1
আপনার উত্তরটি সঠিক নয় কারণ এটি অনির্দিষ্ট করা হয়েছে যে সময় লুপটি সাব-শেলের মধ্যে রয়েছে বা অগ্রভাগ প্রক্রিয়া কিনা। প্রকৃত শেলটি নির্বিশেষে, returnবিবৃতিটি একটি ফাংশনে এবং সুতরাং আইনী legal ফলস্বরূপ আচরণটি অনির্ধারিত।
সুদৃশ্য

বাশ ম্যানুয়াল পৃষ্ঠাতে ফ্যাক্ট পাইপ উপাদানগুলি সাব-শেলের মধ্যে থাকা অবস্থায় আপনাকে এটি একটি অনিবন্ধিত আচরণ হিসাবে লেখা উচিত নয়। আপনার প্যাসিক্স অনুমোদিত আচরণগুলি নির্দিষ্ট করার সময় আচরণটি সম্ভবত সংজ্ঞায়িত চশমার উপর ভিত্তি করে লেখা উচিত নয়। আপনি কোনও ব্যাশ বাগের সন্দেহ করবেন না যখন ব্যাশ কোনও ফাংশনে ফিরে আসার অনুমতি দিয়ে POSIX মান অনুসরণ করে তবে বাইরে নয়।
jlliagre

17

এটি কোনও বাগ নয় bashতবে এর নথিভুক্ত আচরণ :

পাইপলাইনের প্রতিটি কমান্ড তার নিজস্ব সাবশেলে কার্যকর করা হয়

returnনির্দেশ একটি ফাংশন সংজ্ঞা ভিতরে বৈধ হচ্ছে কিন্তু একটি subshell হচ্ছে পাশাপাশি, তাই পরবর্তী নির্দেশ তার পিতা বা মাতা শেল প্রভাবিত করে না, হয় echoনির্বিশেষে মৃত্যুদন্ড কার্যকর করা হয়। তবুও এটি একটি পোর্টেবল শেল নির্মাণ কারণ পসিক্স স্ট্যান্ডার্ড একটি পাইপলাইন রচনা কমান্ডগুলিকে একটি সাবশেল (ডিফল্ট) বা উপরেরটি (অনুমোদিত এক্সটেনশন) এর মাধ্যমে কার্যকর করতে দেয়।

অতিরিক্তভাবে, মাল্টি-কমান্ড পাইপলাইনের প্রতিটি কমান্ড সাব-শেল পরিবেশে থাকে; এক্সটেনশন হিসাবে, তবে, পাইপলাইনের যে কোনও বা সমস্ত কমান্ড বর্তমান পরিবেশে কার্যকর করা যেতে পারে। অন্যান্য সমস্ত কমান্ড বর্তমান শেল পরিবেশে কার্যকর করা হবে।

আশা করি, আপনি বেশ bashকয়েকটি বিকল্পের সাথে আপনার প্রত্যাশা মতো আচরণ করতে বলতে পারেন:

$ set +m # disable job control
$ shopt -s lastpipe # do not run the last command of a pipeline a subshell 
$ o(){ echo | while read -r; do return 0; done; echo $?;}
$ o
$          <- nothing is printed here

1
যেহেতু returnফাংশনটি ছাড়বে না bash: return: can only `return' from a function or sourced script, ব্যবহারকারীটি ফাংশনটি ফিরে আসবে তা ভ্রান্ত ধারণা দেওয়ার পরিবর্তে শেলটি প্রিন্ট করা থাকলে কী আরও বোঝা যাবে না ?
তেরেসা ই জুনিয়র

2
ডকুমেন্টেশনে আমি কোথাও দেখতে পাচ্ছি না বলেছে সাব-শেলের অভ্যন্তরে ফিরে আসাটি বৈধ। আমি বাজি দিয়েছি যে এই বৈশিষ্ট্যটি ksh থেকে অনুলিপি করা হয়েছিল, ফাংশনের বাইরে রিটার্ন স্টেটমেন্ট বা উত্সাহিত স্ক্রিপ্টটি প্রস্থানের মতো আচরণ করে । আমি আসল বোর্ন শেল সম্পর্কে নিশ্চিত নই
cuonglm

1
@ জেলিয়াগ্র্রে: টেরেসা যা চাইছেন তার পরিভাষা সম্পর্কে বিভ্রান্ত হতে পারে, তবে আপনি যদি সাবস্কেল থেকে কোনও কাজ সম্পাদন করেন তবে বাশকে ডায়াগনস্টিক দেওয়ার বিষয়টি কেন "জটিল" হবে তা আমি দেখতে পাই না return। সর্বোপরি, এটি জানেন যে এটি একটি সাবশেলের মধ্যে রয়েছে, যেমন $BASH_SUBSHELLভেরিয়েবল দ্বারা প্রমাণিত । সবচেয়ে বড় সমস্যা হ'ল এটি মিথ্যা ইতিবাচক দিকে পরিচালিত করতে পারে; যে ব্যবহারকারী কীভাবে সাবহেলগুলি কাজ করে তা বোঝে এমন লিখিত স্ক্রিপ্ট থাকতে পারে যা সাবসেল বাতিল করার returnপরিবর্তে ব্যবহার করে exit। (এবং অবশ্যই, এখানে বৈধ কেস রয়েছে যেখানে কেউ ভেরিয়েবল সেট করতে বা cdসাবসেলে একটি করতে পারে ))
স্কট

1
@ স্কট আমি মনে করি আমি পরিস্থিতিটি ভালভাবে বুঝতে পেরেছি। একটি পাইপ একটি সাবশেল তৈরি করে, এবং returnআসল ফাংশনের অভ্যন্তরে থাকায় ব্যর্থ হওয়ার পরিবর্তে সাবশেল থেকে ফিরে আসে। সমস্যাটি হ'ল help returnবিশেষভাবে বলে: Causes a function or sourced script to exit with the return value specified by N.ডকুমেন্টেশন পড়া থেকে যে কোনও ব্যবহারকারী কমপক্ষে ব্যর্থ বা একটি সতর্কতা মুদ্রণ করবে বলে আশা করবে তবে কখনও এর মতো আচরণ করবে না exit
তেরেসা ই জুনিয়র

1
আমার কাছে মনে হয়েছে যে যে কেউ return ফাংশনটিতে (মূল শেল প্রসেসে) ফাংশন থেকে ফিরে আসার জন্য সাব-শেল-এ প্রত্যাশা রাখে তারা সাবশেলগুলি খুব ভাল বুঝতে পারে না। বিপরীতভাবে, আমি এমন একটি পাঠক আশা করব যা সাবস্কেলগুলি বুঝতে পারে return কোনও ফাংশনটিতে একটি সাব - শেলের মধ্যে আশা করে সাবস্কেলটি সমাপ্ত করার জন্য, ঠিক তেমনই exit
স্কট

6

প্রতি POSIX ডকুমেন্টেশন, ব্যবহার returnবা ফাংশন বাইরে sourced স্ক্রিপ্ট অনির্দিষ্ট । সুতরাং, এটি পরিচালনা করার জন্য আপনার শেলের উপর নির্ভর করে।

SystemV শেল ত্রুটি, প্রতিবেদন যখন হবে ksh, returnবা মত ফাংশনের বাইরে sourced স্ক্রিপ্ট আচরণ exit। অন্যান্য বেশিরভাগ পসিক্স শেল এবং স্কিলির oshশও এরকম আচরণ করে:

$ for s in /bin/*sh /opt/schily/bin/osh; do
  printf '<%s>\n' $s
  $s -c '
    o(){ echo | while read l; do return 0; done; echo $?;}; o
  '
done
</bin/bash>
0
</bin/dash>
0
</bin/ksh>
</bin/lksh>
0
</bin/mksh>
0
</bin/pdksh>
0
</bin/posh>
0
</bin/sh>
0
</bin/yash>
0
</bin/zsh>
</opt/schily/bin/osh>
0

kshএবং zshআউটপুট দেয়নি কারণ এই শেলগুলির পাইপের শেষ অংশটি সাব-শেলের পরিবর্তে বর্তমান শেলটিতে কার্যকর হয়েছিল। রিটার্নের বিবৃতিটি বর্তমান শেল পরিবেশকে প্রভাবিত করে যা ফাংশন বলে, কোনও কিছু না ছাপিয়ে তত্ক্ষণাত ফাংশনটি ফিরিয়ে দেয়।

ইন্টারেক্টিভ সেশনে, bashকেবল ত্রুটির প্রতিবেদন করুন তবে শেলটি শেষ করেনি, ত্রুটিটির প্রতিবেদন করেছেন এবং শেলটি schily's oshসমাপ্ত করেছেন:

$ for s in /bin/*sh; do printf '<%s>\n' $s; $s -ci 'return 1; echo 1'; done
</bin/bash>
bash: return: can only `return' from a function or sourced script
1
</bin/dash>
</bin/ksh>
</bin/lksh>
</bin/mksh>
</bin/pdksh>
</bin/posh>
</bin/sh>
</bin/yash>
</bin/zsh>
</opt/schily/bin/osh>
$ cannot return when not in function

( zshইন্টারেক্টিভ সেশন এবং আউটপুটে টার্মিনালটি সমাপ্ত হয় না bash, yashএবং schily's oshত্রুটির কথা জানায় তবে শেলটি শেষ করে না)


1
এটি যুক্তিযুক্ত হতে পারে এখানে কোনও ফাংশনের অভ্যন্তরেreturn ব্যবহৃত হয় ।
jlliagre

1
@jlliagre: তুমি কি নিশ্চিত বলতে চাচ্ছি, returnভিতরে ব্যবহার ছিল subshell ভিতরে ফাংশন ছাড়া kshএবং zsh
cuonglm

2
আমার অর্থ একটি ফাংশনের ভিতরে থাকা একটি সাবশেলের অভ্যন্তরে থাকা মানেই সেই ফাংশনের বাইরে থাকা অর্থাত্ স্ট্যান্ডার্ড স্টেটের পাইপলাইন উপাদানগুলির মধ্যে কিছুই নেই যেখানে তারা অবস্থিত সেই ফাংশনের বাইরে বলে বিবেচিত হবে। এটি ওপেন গ্রুপের দ্বারা পরিষ্কার করার প্রাপ্য হবে।
jlliagre

3
আমি মনে করি না। এটি ফাংশনের বাইরে। শেল যা ফাংশন বলা হয় এবং subshell যা মৃত্যুদন্ড কার্যকর আগমন ভিন্ন।
cuonglm

আমি আপনার যুক্তিটি বুঝতে পারি যা সঠিকভাবে বিষয়টি ব্যাখ্যা করে, আমার বক্তব্যটি পসিক্স স্ট্যান্ডার্ডে বর্ণিত শেল ব্যাকরণ অনুযায়ী, পাইপলাইনটি যৌগিক-তালিকার অংশ যা যৌগিক কমান্ডের অংশ যা ফাংশনের মূল অংশ। কোথাও এটি পাইপলাইন উপাদান ফাংশনের বাইরে বিবেচনা করা হয় বলে উল্লেখ করা হয়। ঠিক যেমন আমি কোনও গাড়ীতে আছি এবং সেই গাড়িটি গ্যারেজে দাঁড়িয়ে আছে, আমি ধরে নিতে পারি যে আমিও সেই গ্যারেজে আছি ;-)
jlliagre

4

আমি মনে করি যে আপনি প্রত্যাশিত আচরণ পেয়েছেন, ব্যাশে, পাইপলাইনের প্রতিটি কমান্ড একটি সাব-শেলের মধ্যে কার্যকর করা হয়। আপনি আপনার ফাংশনটির একটি বৈশ্বিক চলক সংশোধন করার চেষ্টা করে নিজেকে বিশ্বাসী করতে পারেন:

foo(){ x=42; : | x=3; echo "x==$x";}

যাইহোক, রিটার্নটি কাজ করছে তবে এটি সাব-শেল থেকে ফিরে আসে। আবার আপনি এটি পরীক্ষা করতে পারেন:

foo(){ : | return 1; echo$?; echo "This should not be printed.";}

নিম্নলিখিত ফলাফল আউটপুট হবে:

1
This should not be printed.

সুতরাং রিটার্ন স্টেটমেন্টটি সঠিকভাবে সাবশেল থেকে বেরিয়েছে


2
সুতরাং, ফাংশন থেকে প্রস্থান করতে, ব্যবহার করুন foo(){ : | return 1 || return 2; echo$?; echo "This should not be printed.";}; foo; echo $?এবং এর ফলাফল পাবেন 2। কিন্তু স্বচ্ছতার জন্য আমি তৈরি করতে পারতাম return 1হতে exit 1
dubiousjim

যাইহোক, পাইপলাইনের সমস্ত সদস্য (এক নয় সমস্তই) সাবসেলের মধ্যে মৃত্যুদণ্ড কার্যকর করা হয়েছে তার সত্যতা কি কিছু আছে ?
ইনকিনিস মিসেসি


1

আরও সাধারণ উত্তর হ'ল বাশ এবং কিছু অন্যান্য শেল সাধারণত পাইপলাইনের সমস্ত উপাদানকে পৃথক প্রক্রিয়াতে রাখে। কমান্ড লাইন হলে এটি যুক্তিযুক্ত

প্রোগ্রাম 1 | প্রোগ্রাম 2 | প্রোগ্রাম 3

প্রোগ্রামগুলি যেহেতু সাধারণত পৃথক প্রক্রিয়াগুলিতে চালিত হয় (আপনি না বললে )। তবে এটি চমক হিসাবে আসতে পারেexec program

কমান্ড 1 | কমান্ড 2 | কমান্ড 3

যেখানে কিছু বা সমস্ত কমান্ড অন্তর্নির্মিত কমান্ড। তুচ্ছ উদাহরণের মধ্যে রয়েছে:

$ a=0
$ echo | a=1
$ echo "$a"
0
$ cd /
$ echo | cd /tmp
$ pwd
/

আরও কিছুটা বাস্তব উদাহরণ

$ t=0
$ ps | while read pid rest_of_line
> do
>     : $((t+=pid))
> done
$ echo "$t"
0

যেখানে সমগ্র while... do... doneএবং তার পরিবর্তন তাই লুপ একটি subprocess পুরা হয় tলুপ শেষ হওয়ার পরে প্রধান শেল কাছে দৃশ্যমান নয়। এবং ঠিক whileএটিই আপনি করছেন - লুপের মধ্যে পাইপিং করা , লুপটিকে সাব-শেল হিসাবে চালিত করে এবং তারপরে সাব-শেল থেকে ফিরে আসার চেষ্টা করে।

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