(প্রস্থান 1) স্ক্রিপ্ট থেকে প্রস্থান করে না কেন?


48

আমার একটি স্ক্রিপ্ট রয়েছে, যখন আমি এটি চাইলে প্রস্থান হয় না।

একই ত্রুটির সাথে একটি উদাহরণ স্ক্রিপ্ট হ'ল:

#!/bin/bash

function bla() {
    return 1
}

bla || ( echo '1' ; exit 1 )

echo '2'

আমি আউটপুটটি ধরে নেব:

:~$ ./test.sh
1
:~$

তবে আমি আসলে দেখতে পাচ্ছি:

:~$ ./test.sh
1
2
:~$

()কমান্ড শৃঙ্খলাবদ্ধভাবে কি কোনওভাবে একটি সুযোগ তৈরি করে? exitস্ক্রিপ্ট না থাকলে কী বাইরে বের হচ্ছে?


5
এটিতে একটি একক শব্দের উত্তরের জন্য আহ্বান জানানো হয়েছে: সাবশেল
জোশুয়া

উত্তর:


87

()সাবশেলে কমান্ডগুলি চালিত করে, সুতরাং exitআপনি সাব-শেল থেকে প্রস্থান করছেন এবং প্যারেন্ট শেলটিতে ফিরে আসছেন। {}আপনি যদি বর্তমান শেলের কমান্ডগুলি চালাতে চান তবে ধনুর্বন্ধনী ব্যবহার করুন ।

বাশ ম্যানুয়াল থেকে:

(তালিকা) তালিকাটি একটি সাব-শেল পরিবেশে কার্যকর করা হয়। পরিবর্তনশীল অ্যাসাইনমেন্ট এবং বিল্টিন কমান্ডগুলি যা শেলের পরিবেশকে প্রভাবিত করে কমান্ডটি সম্পূর্ণ হওয়ার পরে কার্যকর হয় না। রিটার্নের স্থিতি হল তালিকার প্রস্থান স্থিতি।

{তালিকা; } তালিকা কেবল বর্তমান শেল পরিবেশে মৃত্যুদন্ড কার্যকর করা হয়। তালিকাটি অবশ্যই একটি নতুন লাইন বা সেমিকোলন দিয়ে শেষ করতে হবে। এটি একটি গ্রুপ কমান্ড হিসাবে পরিচিত। রিটার্নের স্থিতি হল তালিকার প্রস্থান স্থিতি। মনে রাখবেন যে মেটাচার্যাক্টারের বিপরীতে (এবং), {এবং reserved সংরক্ষিত শব্দ এবং যেখানে অবশ্যই কোনও সংরক্ষিত শব্দের স্বীকৃতি দেওয়ার অনুমতি দেওয়া আছে সেখানে অবশ্যই আবশ্যক। যেহেতু তারা কোনও শব্দের বিরতি সৃষ্টি করে না, তাই তাদের অবশ্যই হোয়াইটস্পেস বা অন্য শেল মেটাচারাক্টারের দ্বারা তালিকা থেকে আলাদা করতে হবে।

এটি উল্লেখ করার মতো যে শেল সিনট্যাক্সটি বেশ সামঞ্জস্যপূর্ণ এবং সাব-শেল অন্যান্য ()নির্মাণে যেমন কমান্ড সাবস্টিটিউশন (পুরানো-শৈলীর `..`সিনট্যাক্সের সাথেও ) বা প্রক্রিয়া প্রতিস্থাপনে অংশ নেয়, সুতরাং নিম্নলিখিতটি বর্তমান শেল থেকে বেরিয়ে আসবে না:

echo $(exit)
cat <(exit)

কমান্ডগুলি সুস্পষ্টভাবে ভিতরে স্থাপন করা হলে সাবহেলগুলি জড়িত থাকার বিষয়টি স্পষ্ট হতে পারে (), তবুও কম দৃশ্যমান সত্যটি এই অন্যান্য কাঠামোর মধ্যেও তৈরি হয়েছে:

  • কমান্ড পটভূমিতে শুরু হয়েছিল

    exit &

    বর্তমান শেলটি প্রস্থান করে না কারণ (পরে man bash)

    যদি কমান্ডটি কন্ট্রোল অপারেটর & এর মাধ্যমে সমাপ্ত হয়, তবে শেলটি একটি সাবশেলের পটভূমিতে কমান্ডটি কার্যকর করে। শেলটি কমান্ডটি শেষ হওয়ার জন্য অপেক্ষা করে না, এবং ফেরতের স্থিতি 0 হয়।

  • পাইপলাইন

    exit | echo foo

    এখনও কেবল সাব-শেল থেকে বেরিয়ে আসে।

    তবে এই বিষয়ে বিভিন্ন শাঁস আলাদাভাবে আচরণ করে। উদাহরণস্বরূপ bashরাখে পৃথক subshells মধ্যে পাইপলাইন সব উপাদান (যদি না আপনি ব্যবহার lastpipeআমন্ত্রণ যেখানে কাজ নিয়ন্ত্রণ সক্রিয় করা হয় না বিকল্প), কিন্তু যেমন AT & T kshzshবর্তমান শেল ভিতরে শেষ অংশ (উভয় আচরণে POSIX দ্বারা অনুমোদিত হয়) চালানো। এইভাবে

    exit | exit | exit

    মূলত ব্যাশে কিছুই করে না, তবে শেষের কারণে zsh থেকে বেরিয়ে আসে exit

  • coproc exitএছাড়াও exitএকটি subhell চালায় ।


5
আহ। এখন সমস্ত জায়গাগুলি সন্ধানের জন্য, যেখানে আমার পূর্বসূরীরা ভুল ধনুর্বন্ধনী ব্যবহার করেছে। অন্তর্দৃষ্টি জন্য ধন্যবাদ।
মিনিক্স

10
ম্যান পৃষ্ঠায় ব্যবধানের যত্ন সহকারে নোট করুন: {এবং }বাক্য গঠন নয়, এগুলি সংরক্ষণাগারযুক্ত শব্দ এবং ফাঁকা স্থান দ্বারা আবশ্যক, এবং তালিকাটি অবশ্যই একটি কমান্ড টার্মিনেটর (সেমিকোলন, নিউলাইন,
অ্যাম্পারস্যান্ড

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

5
@ ড্যানশেপার্ড এটি অন্য প্রক্রিয়া, তবে (echo $$)প্যারেন্ট শেল আইডি প্রিন্ট করে কারণ সাব- শেল $$তৈরির আগেই প্রসারিত হয়। আসলে মুদ্রণ subshell প্রক্রিয়া ID চতুর সৃষ্টি করে, সেক্ষেত্রে দেখতে stackoverflow.com/questions/9119885/...
jimmij

@ জিম্মিজ, সাব-শেল তৈরির $$আগে এটি কীভাবে প্রসারিত হবে , এবং এখনও সাব-শেলের $BASHPIDসঠিক মানটি দেখায়?
ওয়াইল্ডকার্ড

13

সাব- exitশেলের মধ্যে সম্পাদন করা একটি ক্ষতি:

#!/bin/bash
function calc { echo 42; exit 1; }
echo $(calc)

স্ক্রিপ্টটি 42 টি মুদ্রণ করে, রিটার্ন কোড সহ সাবশেল থেকে প্রস্থান করে 1এবং স্ক্রিপ্টটি দিয়ে চালিয়ে যায়। এমনকি কলটি প্রতিস্থাপন করাও echo $(CALC) || exit 1সহায়তা করে না কারণ রিটার্ন কোডটি echo0 এর রিটার্ন কোড নির্বিশেষে 0 হয় calc। এবং calcআগে মৃত্যুদন্ড কার্যকর করা হয় echo

এমনকি আরও বিরক্তিকর প্রভাব thwarting হয় exitসেটিকে মোড়কে localনিম্নলিখিত লিপিতে মত builtin। আমি যখন কোনও ইনপুট মান যাচাই করতে কোনও ফাংশন লিখেছিলাম তখন আমি সমস্যার জন্য হোঁচট খেয়েছি। উদাহরণ:

আমি 20141211.logআজ বছরের জন্য "বছরের মাসের দিন.লগ" নামে একটি ফাইল তৈরি করতে চাই । তারিখটি কোনও ব্যবহারকারীর ইনপুট যা যুক্তিসঙ্গত মান প্রদান করতে ব্যর্থ হতে পারে। অতএব, আমার ফাংশনে fnameআমি dateব্যবহারকারীর ইনপুটটির বৈধতা যাচাই করতে ফেরতের মানটি পরীক্ষা করি :

#!/bin/bash

doit ()
    {
    local FNAME=$(fname "$1") || exit 1
    touch "${FNAME}"
    }

fname ()
    {
    date +"%Y%m%d.log" -d"$1" 2>/dev/null
    if [ "$?" != 0 ] ; then
        echo "fname reports \"Illegal Date\"" >&2
        exit 1
    fi
    }

doit "$1"

ভাল লাগছে। স্ক্রিপ্টটির নাম দেওয়া হোক s.sh। যদি ব্যবহারকারী স্ক্রিপ্টটি সাথে কল করে ./s.sh "Thu Dec 11 20:45:49 CET 2014"তবে ফাইলটি 20141211.logতৈরি হয়। তবে, যদি ব্যবহারকারী টাইপ করে ./s.sh "Thu hec 11 20:45:49 CET 2014"তবে স্ক্রিপ্ট আউটপুট দেয়:

fname reports "Illegal Date"
touch: cannot touch ‘’: No such file or directory

লাইনটি fname…জানিয়েছে যে সাবসেলের মধ্যে খারাপ ইনপুট ডেটা সনাক্ত করা হয়েছে। তবে লাইনের exit 1শেষে local …কখনই ট্রিগার হয় না কারণ localনির্দেশ সর্বদা ফিরে আসে 0। এটি কারণ পরেlocal মৃত্যুদন্ড কার্যকর করা হয় $(fname) এবং এভাবে তার রিটার্ন কোডটি ওভাররাইট করে। এবং সে কারণে, স্ক্রিপ্টটি অবিরত থাকে এবং touchএকটি খালি প্যারামিটার সহ প্রার্থনা করে । এই উদাহরণটি সহজ তবে বাশের আচরণ একটি বাস্তব প্রয়োগে বেশ বিভ্রান্তিকর হতে পারে। আমি জানি, প্রকৃত প্রোগ্রামাররা স্থানীয় ব্যবহার করে না ☺

এটি পরিষ্কার করার জন্য: localস্ক্রিপ্টটি যখন কোনও অবৈধ তারিখ প্রবেশ করা হয় তখন প্রত্যাশা অনুযায়ী স্ক্র্যাপটি বাতিল হয়।

ফিক্সটি লাইনের মতো বিভক্ত করতে হবে

local FNAME
FNAME=$(fname "$1") || exit 1

অদ্ভুত আচরণটি ব্যাশের localম্যান পেজের মধ্যে ডকুমেন্টেশনের সাথে সঙ্গতিপূর্ণ: "রিটার্নের স্থিতি 0 হয় যদি না কোনও ফাংশনের বাইরে স্থানীয় ব্যবহার করা হয়, একটি অবৈধ নাম সরবরাহ করা হয় না, বা নামটি কেবল পঠনযোগ্য পরিবর্তনশীল" "

বাগ না হওয়া সত্ত্বেও আমি অনুভব করি যে বাশের আচরণটি বিপরীত। আমি মৃত্যুদন্ডের ক্রম সম্পর্কে সচেতন local, তবুও কোনও ভাঙা অ্যাসাইনমেন্টটি মাস্ক করা উচিত নয়।

আমার প্রাথমিক উত্তরে কিছু ভুলত্রুটি রয়েছে। মাইক্রোজারের সাথে একটি প্রকাশ্য এবং গভীর আলোচনার পরে (তার জন্য আপনাকে ধন্যবাদ) আমি সেগুলি স্থির করতে গিয়েছিলাম।


@ মিমকিজার: প্রাসঙ্গিকতা প্রদর্শনের জন্য আমি একটি উদাহরণ যুক্ত করেছি।
Hermannk

@ মিমকিজার: হ্যাঁ, আপনি ঠিক বলেছেন। এমনকি টর্সারও। কিন্তু সমস্যা এখনও আছে।
Hermannk

@ মিমকিজার: দুঃখিত, আমার উদাহরণটি ভেঙে গেছে। আমি পরীক্ষা ভুলে গেছি doit()
Hermannk


2

আসল সমাধান:

#!/bin/bash

function bla() {
    return 1
}

bla || { echo '1'; exit 1; }

echo '2'

ত্রুটি দলবদ্ধকরণ কেবল তখনই কার্যকর করা হবে যদি blaকোনও ত্রুটির স্থিতি ফেরত দেয় এবং exitসাবস্কেলে না থাকে তাই পুরো স্ক্রিপ্টটি বন্ধ হয়ে যায়।


1

বন্ধনীগুলি একটি সাব-শেল শুরু করে এবং প্রস্থানটি কেবল সেই সাবশেল থেকে প্রস্থান করে।

সাবসেলটি $?যদি বেরিয়ে আসে তবে আপনি স্ক্রিপ্ট থেকে বেরিয়ে আসতে আপনার স্ক্রিপ্টে এক্সটিকোডটি পড়তে এবং এটি যুক্ত করতে পারেন:

#!/bin/bash

function bla() {
    return 1
}

bla || ( echo '1' ; exit 1 )

exitcode=$?
if [ $exitcode != 0 ]; then exit $exitcode; fi

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