আমি একটি POSIX শেল ফাংশন যা স্থানীয়ভাবে একটি শেল builtin বা কোনো ফাংশন নামস্থান ব্যবহার করা যেতে পারে লিখেছি ksh93, dash, mksh, অথবা bash (বিশেষভাবে নামে কারণ আমি ব্যক্তিগতভাবে এই সব কাজ করার এটা নিশ্চিত করেছেন) । আমি যে শেলগুলিতে এটি পরীক্ষা করেছিলাম তার মধ্যে এটি কেবল আমার প্রত্যাশা পূরণ করতে ব্যর্থ হয়েছিল yashএবং আমি কখনই এটির কাজ করার আশাও করি নি zsh। আমি পরীক্ষা করিনি posh। আমি poshকিছুক্ষণ আগে কোনও আশা ছেড়ে দিয়েছি এবং এটি কিছু সময় ইনস্টল করি নি। সম্ভবত এটি কাজ করে posh...?
আমি বলি এটি পসিক্স কারণ স্পেসিফিকেশনটি পড়ার মাধ্যমে এটি একটি মৌলিক ইউটিলিটির নির্দিষ্ট আচরণের সুবিধা গ্রহণ করে তবে স্বীকারোক্তি হিসাবে স্পেসিফিকেশনটি এই বিষয়ে অস্পষ্ট এবং কমপক্ষে একজন ব্যক্তি দৃশ্যত আমার সাথে একমত নন। সাধারণত আমার এইটির সাথে আমার মতবিরোধ ছিল আমি শেষ পর্যন্ত ত্রুটিটি আমার নিজের বলে খুঁজে পেয়েছি এবং সম্ভবত স্পেসিফিকেশনটি সম্পর্কেও আমি এই সময় ভুল হয়েছি, কিন্তু আমি যখন তাকে আরও জিজ্ঞাসাবাদ করি তখন তিনি কোনও উত্তর দেননি।
আমি যেমন বলেছি, যদিও এটি পূর্বোক্ত শেলগুলিতে অবশ্যই কাজ করে এবং মূলত নিম্নলিখিত পদ্ধতিতে এটি কাজ করে:
some_fn(){ x=3; echo "$x"; }
x=
x=local command eval some_fn
echo "${x:-empty}"
3
empty
commandকমান্ড একটি মূলত প্রাপ্তিসাধ্য উপযোগিতা ও প্রাক এক হিসাবে উল্লেখ করা হয় $PATH; 'd builtins। এর নির্দিষ্ট বৈশিষ্ট্যগুলির মধ্যে একটি হ'ল বিশেষ বিল্টিন ইউটিলিটিগুলিকে কল করার সময় তার নিজস্ব পরিবেশে গুটিয়ে রাখা, এবং তাই ...
{ sh -c ' x=5 set --; echo "$x"
x=6 command set --; echo "$x"
exec <""; echo uh_oh'
sh -c ' command exec <""; echo still here'
}
5
5
sh: 3: cannot open : No such file
sh: 1: cannot open : No such file
still here
... উপরের কমান্ড-লাইন উভয় কার্যভারের আচরণটি নির্দিষ্টভাবে সঠিক। উভয় ত্রুটির শর্তের আচরণও সঠিক এবং এটি স্পেসিফিকেশন থেকে প্রায় সম্পূর্ণরূপে নকল হয়েছে। বর্তমান শেল পরিবেশকে প্রভাবিত করার জন্য ফাংশন বা বিশেষ বিল্টিনের কমান্ড-লাইনের সাথে পূর্বনির্ধারিত অ্যাসাইনমেন্টগুলি নির্দিষ্ট করা হয়। তেমনি, পুনঃনির্দেশ ত্রুটিগুলি মারাত্মক হিসাবে নির্দিষ্ট করা হয় যখন সেগুলির মধ্যে দুটিতে নির্দেশ করা হয়। commandএই ক্ষেত্রে বিশেষ বিল্টিনগুলির বিশেষ চিকিত্সা দমন করার জন্য নির্দিষ্ট করা হয়েছে, এবং পুনঃনির্দেশের কেসটি স্পেসিফিকেশনটিতে উদাহরণস্বরূপ প্রদর্শিত হয়।
অন্যদিকে নিয়মিত বিল্টিনগুলি সাব-শেল পরিবেশেcommand চলার জন্য নির্দিষ্ট করা হয় - যার অর্থ অন্য প্রক্রিয়াটির অর্থ এই নয় যে কেবল এটি একের থেকে মৌলিকভাবে পৃথক হওয়া উচিত। নিয়মিত অন্তর্নির্মিত কল করার ফলাফলগুলি সর্বদা সদৃশ হওয়া উচিত যা একইভাবে সক্ষম 'ডি কমান্ড থেকে প্রাপ্ত হতে পারে । এবং তাই...$PATH
na=not_applicable_to_read
na= read var1 na na var2 <<"" ; echo "$var1" "$na" "$var2"
word1 other words word2
word1 not_applicable_to_read word2
কিন্তু commandকমান্ডটি শেল ফাংশনগুলিকে কল করতে পারে না এবং তাই নিয়মিত বিল্টিনগুলির জন্য তাদের বিশেষ চিকিত্সা মোটা রেন্ডার করতে ব্যবহার করা যায় না। এটাও স্পষ্ট। প্রকৃতপক্ষে, অনুমানটি বলে যে একটি প্রাথমিক ইউটিলিটি commandহ'ল আপনি এটি অন্য একটি কমান্ডের জন্য নামকরণ করা একটি র্যাপার শেল ফাংশনটির মধ্যে স্ব স্ব-পুনরাবৃত্তি ছাড়াই অন্য কমান্ডটি কল করতে পারেন কারণ এটি ফাংশনটি কল করবে না। এটার মত:
cd(){ command cd -- "$1"; }
আপনি যদি commandসেখানে ব্যবহার না করেন তবে cdফাংশনটি স্ব-পুনরাবৃত্তির জন্য প্রায় অবশ্যই সেগফল্ট করবে।
তবে একটি নিয়মিত অন্তর্নির্মিত হিসাবে যা বিশেষ বিল্টিনকে কল commandকরতে পারে তা সাব-শেল পরিবেশে এটি করতে পারে । এবং তাই, যখন বর্তমান শেল রাষ্ট্রবিরোধী বর্তমান শেল শক্তি লাঠি মধ্যে সংজ্ঞায়িত - অবশ্যই readএর $var1এবং $var2করেনি - কম্যান্ড-লাইন সংজ্ঞায়িত করে অন্তত ফলাফল সম্ভবত উচিত না ...
সাধারণ কমান্ড
যদি কোনও কমান্ড নাম ফলাফল না দেয় বা কমান্ডের নামটি একটি বিশেষ অন্তর্নির্মিত বা ফাংশন হয় তবে চলক কার্যভারগুলি বর্তমান সম্পাদন পরিবেশকে প্রভাবিত করবে। অন্যথায়, ভেরিয়েবল অ্যাসাইনমেন্টগুলি কমান্ডের সঞ্চালনের পরিবেশের জন্য রফতানি করা হবে এবং বর্তমান সম্পাদন পরিবেশকে প্রভাবিত করবে না।
এখন commandনিয়মিত অন্তর্নির্মিত এবং সরাসরি বিশেষ বিল্টিন উভয়কেই ডাকার দক্ষতা হ'ল কমান্ড-লাইনের সংজ্ঞাগুলি সম্পর্কে আমি জানি না এমন সংজ্ঞা সম্পর্কে কেবল এক ধরণের অপ্রত্যাশিত লুফোল, তবে আমি জানি যে কমপক্ষে চারটি শাঁস ইতিমধ্যে commandনামস্থান উল্লেখ সম্মান ।
আর যদিও commandসরাসরি শেল ফাংশন কল করতে পারবেন না, এটা করতে পারেন কল evalহিসাবে দেখায়, এবং তাই পরোক্ষভাবে করতে পারেন। তাই আমি এই ধারণার উপর একটি নেমস্পেসের মোড়ক তৈরি করেছি। এটি যুক্তিগুলির একটি তালিকা নেয়:
ns any=assignments or otherwise=valid names which are not a command then all of its args
... বাদে commandউপরের শব্দটি কেবল একটি হিসাবে স্বীকৃত যদি এটি খালি সঙ্গে পাওয়া যায় $PATH। এছাড়া কমান্ড লাইন নামে শেল ভেরিয়েবল স্থানীয়ভাবে-scoping, এটি যেমন একক ছোট হাতের বর্ণানুক্রমিক নাম এবং অন্যান্য মান বেশী একটি তালিকা সঙ্গে সব পরিবর্তনশীল স্থানীয়ভাবে-সুযোগগুলি $PS3, $PS4, $OPTARG, $OPTIND, $IFS, $PATH, $PWD, $OLDPWDএবং কিছু অন্যদের।
এবং হ্যাঁ, স্থানীয়ভাবে scoping দ্বারা $PWDএবং $OLDPWDভেরিয়েবল এবং পরে স্পষ্টভাবে cdকরতে ing $OLDPWDএবং $PWDএটা মোটামুটি নির্ভরযোগ্যভাবে সুযোগ সাম্প্রতিক কাজ করা পাশাপাশি পারেন। এটি গ্যারান্টিযুক্ত নয়, যদিও এটি বেশ চেষ্টা করে। এটি এর জন্য একটি বিবরণী ধরে রাখে 7<.এবং এর মোড়কের টার্গেটটি কখন তা করে cd -P /dev/fd/7/। যদি বর্তমান কার্যনির্বাহী ডিরেক্টরি unlink()অন্তর্বর্তী হয়ে থাকে তবে এটি অবশ্যই কমপক্ষে এটির মধ্যে আবার পরিবর্তন করতে পারে তবে সেই ক্ষেত্রে একটি কুৎসিত ত্রুটি নির্গত করবে। এবং এটি বিবরণকারী বজায় রাখার কারণে, আমি মনে করি না যে কোনও বুদ্ধিমান কার্নেলের দ্বারা তার মূল ডিভাইসটি আনমাউন্ট করা উচিত নয় (???) ।
এটি স্থানীয়ভাবে শেল বিকল্পগুলিও স্কোপ করে এবং এগুলিকে এমন অবস্থায় পুনরুদ্ধার করে যেখানে এটি মোড়ানো ইউটিলিটি ফিরে আসে। এটি $OPTSবিশেষভাবে বিবেচনা করে যে এটি তার নিজস্ব কপির মধ্যে একটি অনুলিপি বজায় রাখে যা এটি প্রাথমিকভাবে এর মান নির্ধারণ করে $-। কমান্ড-লাইনে সমস্ত অ্যাসাইনমেন্ট পরিচালনা করার পরে এটি set -$OPTSএর মোড়কের টার্গেটটি চালানোর ঠিক আগে করবে । আপনি যদি -$OPTSকমান্ড-লাইনে সংজ্ঞায়িত করেন তবে আপনি নিজের মোড়কের লক্ষ্যমাত্রার শেল বিকল্পগুলি সংজ্ঞায়িত করতে পারেন। লক্ষ্যটি যখন প্রত্যাবর্তন করে তখন এটি set +$- -$OPTSতার নিজস্ব অনুলিপি সহ $OPTS (যা কমান্ড-লাইন সংজ্ঞায়িত দ্বারা প্রভাবিত হয় না) এবং সমস্তকে মূল অবস্থায় ফিরিয়ে আনবে ।
অবশ্যই, returrnমোড়কের টার্গেট বা এর যুক্তিগুলির মাধ্যমে কলারের স্পষ্টভাবে ফাংশনটি আউট করা থেকে কলারকে থামানোর কিছুই নেই । এটি করার ফলে কোনও রাজ্য পুনরুদ্ধার / ক্লিনআপ আটকাতে হবে এটি অন্যথায় চেষ্টা করবে।
এটি তিনটি evalগভীর যেতে প্রয়োজন যে সমস্ত করতে । প্রথমে এটি একটি স্থানীয় সুযোগে নিজেকে গুটিয়ে রাখে, তারপরেই, এটি আর্গুমেন্টে পড়ে, বৈধ শেল নামগুলির জন্য তাদেরকে বৈধ করে তোলে এবং যদি এটি খুঁজে না পায় তবে ত্রুটি সহ প্রস্থান করে। যদি সমস্ত যুক্তি বৈধ হয় এবং শেষ পর্যন্ত কোনওটি command -v "$1"সত্য হওয়ার প্রত্যাশা করে (স্মরণ করুন: $PATHএই মুহুর্তে খালি) এটি evalকমান্ড-লাইনটি আবদ্ধ টার্গেটে বাকী সমস্ত আর্গুমেন্টকে সংজ্ঞায়িত করবে এবং প্রেরণ করবে (যদিও এটি বিশেষ ক্ষেত্রে উপেক্ষা করে ns- কারণ এটি হবে না এটি খুব দরকারী হবে না, এবং তিনটি evalগভীর যথেষ্ট গভীরের চেয়ে গভীর) ।
এটি মূলত এটির মতো কাজ করে:
case $- in (*c*) ... # because set -c doesnt work
esac
_PATH=$PATH PATH= OPTS=$- some=vars \
command eval LOCALS=${list_of_LOCALS}'
for a do i=$((i+1)) # arg ref
if [ "$a" != ns ] && # ns ns would be silly
command -v "$a" &&
! alias "$a" # aliases are hard to run quoted
then eval " PATH=\$_PATH OTHERS=$DEFAULTS $v \
command eval '\''
shift $((i-1)) # leave only tgt in @
case $OPTS in (*different*)
set \"-\${OPTS}\" # init shell opts
esac
\"\$@\" # run simple command
set +$- -$OPTS "$?" # save return, restore opts
'\''"
cd -P /dev/fd/7/ # go whence we came
return "$(($??$?:$1))" # return >0 for cd else $1
else case $a in (*badname*) : get mad;;
# rest of arg sa${v}es
esac
fi; done
' 7<.
কিছু অন্যান্য পুনর্নির্দেশ এবং, এবং কয়েকটি শেল যেভাবে রাখা cহয়েছিল তার সাথে করার জন্য কয়েকটি অদ্ভুত পরীক্ষা রয়েছে $-এবং তারপরে এটি set (???) এর বিকল্প হিসাবে গ্রহণ করতে অস্বীকৃতি জানায় তবে এর সমস্ত আনুষঙ্গিক এবং মূলত কেবল নির্গমন থেকে বাঁচাতে ব্যবহৃত হয় অযাচিত আউটপুট এবং প্রান্ত ক্ষেত্রে অনুরূপ। এবং এটি কিভাবে এটি কাজ করে। এটি এই জিনিসগুলি করতে পারে কারণ এটি কোনও নেস্টেড এর মধ্যে তার মোড়ানো ইউটিলিটি কল করার আগে এটির নিজস্ব স্থানীয় সুযোগ সেট করে।
এটি দীর্ঘ, কারণ আমি এখানে খুব সাবধানী হওয়ার চেষ্টা করি - তিনটি evalsশক্ত is তবে এটির সাহায্যে আপনি এটি করতে পারেন:
ns X=local . /dev/fd/0 <<""; echo "$X" "$Y"
X=still_local
Y=global
echo "$X" "$Y"
still_local global
global
এটি আরও একধাপ এগিয়ে নিয়ে যাওয়া এবং অবিচ্ছিন্নভাবে মোড়ানো ইউটিলিটির স্থানীয় ক্ষেত্রের নাম স্পেস করা খুব কঠিন হওয়া উচিত নয়। এমনকি লিখিত হিসাবে এটি ইতিমধ্যে $LOCALSমোড়ানো ইউটিলিটিতে একটি ভেরিয়েবলকে সংজ্ঞায়িত করে যা মোড়ানো ইউটিলিটির পরিবেশে সংজ্ঞায়িত সমস্ত নামের মধ্যে কেবল একটি স্থান পৃথকীকরণের তালিকা নিয়ে গঠিত।
ভালো লেগেছে:
ns var1=something var2= eval ' printf "%-10s%-10s%-10s%s\n" $LOCALS '
... যা পুরোপুরি নিরাপদ - $IFSএটির ডিফল্ট মান হিসাবে স্যানিটাইজ করা হয়েছে এবং আপনি নিজেরাই $LOCALSকমান্ড লাইনে সেট না করে কেবল বৈধ শেল নামগুলি এটিকে তৈরি করে । এমনকি যদি বিভক্ত চলকটিতে গ্লোব অক্ষরও থাকতে পারে তবে OPTS=fতাদের প্রসারিত হওয়া নিষেধ করার জন্য মোড়কযুক্ত ইউটিলিটির জন্য আপনি কমান্ড-লাইনে সেট করতে পারেন । যে কোনো ক্ষেত্রে:
LOCALS ARG0 ARGC HOME
IFS OLDPWD OPTARG OPTIND
OPTS PATH PS3 PS4
PWD a b c
d e f g
h i j k
l m n o
p q r s
t u v w
x y z _
bel bs cr esc
ht ff lf vt
lb dq ds rb
sq var1 var2
এবং এখানে ফাংশন। বিস্তৃতি \এড়াতে সমস্ত কমান্ড ডাব্লু / উপসর্গযুক্ত হয় alias:
ns(){ ${1+":"} return
case $- in
(c|"") ! set "OPTS=" "$@"
;; (*c*) ! set "OPTS=${-%c*}${-#*c}" "$@"
;; (*) set "OPTS=$-" "$@"
;; esac
OPTS=${1#*=} _PATH=$PATH PATH= LOCALS= lf='
' rb=\} sq=\' l= a= i=0 v= __=$_ IFS=" ""
" command eval LOCALS=\"LOCALS \
ARG0 ARGC HOME IFS OLDPWD OPTARG OPTIND OPTS \
PATH PS3 PS4 PWD a b c d e f g h i j k l m n \
o p q r s t u v w x y z _ bel bs cr esc ht ff \
lf vt lb dq ds rb sq'"
for a do i=$((i+1))
if \[ ns != "$a" ] &&
\command -v "$a" >&9 &&
! \alias "${a%%=*}" >&9 2>&9
then \eval 7>&- '\' \
'ARGC=$((-i+$#)) ARG0=$a HOME=~' \
'OLDPWD=$OLDPWD PATH=$_PATH IFS=$IFS' \
'OPTARG=$OPTARG PWD=$PWD OPTIND=1' \
'PS3=$PS3 _=$__ PS4=$PS4 LOCALS=$LOCALS' \
'a= b= c= d= e= f= g= i=0 j= k= l= m= n= o=' \
'p= q= r= s= t= u= v= w= x=0 y= z= ht=\ ' \
'cr=^M bs=^H ff=^L vt=^K esc=^[ bel=^G lf=$lf' \
'dq=\" sq=$sq ds=$ lb=\{ rb=\}' \''"$v' \
'\command eval 9>&2 2>&- '\' \
'\shift $((i-1));' \
'case \${OPTS##*[!A-Za-z]*} in' \
'(*[!c$OPTS]*) >&- 2>&9"'\' \
'\set -"${OPTS%c*}${OPTS#*c}"' \
';;esac; "$@" 2>&9 9>&-; PS4= ' \
'\set +"${-%c*}${-#*c}"'\'\" \
-'$OPTS \"\$?\"$sq";' \
' \cd -- "${OLDPWD:-$PWD}"
\cd -P ${ANDROID_SYSTEM+"/proc/self/fd/7"} /dev/fd/7/
\return "$(($??$?:$1))"
else case ${a%%=*} in
([0-9]*|""|*[!_[:alnum:]]*)
\printf "%s: \${$i}: Invalid name: %s\n" \
>&2 "$0: ns()" "'\''${a%%=*}'\''"
\return 2
;; ("$a") v="$v $a=\$$a"
;; (*) v="$v ${a%%=*}=\${$i#*=}"
;; esac
case " $LOCALS " in (*" ${a%%=*} "*)
;; (*) LOCALS=$LOCALS" ${a%%=*}"
;; esac
fi
done' 7<. 9<>/dev/null
}
( easiest thing ever )। তবে আপনি যা করছেন তা পুরোপুরি নয়। আমি অনুমান করি আপনি করতে পারেন( stuff in subshell; exec env ) | sed 's/^/namespace_/'এবংevalপিতামাতার শেলের ফলাফল কিন্তু এটি একদম বাজে।