এই চাহিদা 4.1 bash যদি আপনি ব্যবহার {fd}
বা local -n
।
বাকিদের বাশ 3.x এ কাজ করা উচিত আশা করি। কারণে আমি পুরোপুরি নিশ্চিত নই printf %q
- এটি সম্ভবত ব্যাশ 4 বৈশিষ্ট্য।
সারসংক্ষেপ
পছন্দসই প্রভাবটি সংরক্ষণাগারভুক্ত করতে আপনার উদাহরণটি নিম্নরূপে সংশোধন করা যেতে পারে:
_passback() { while [ 1 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; return $1; }
passback() { _passback "$@" "$?"; }
_capture() { { out="$("${@:2}" 3<&-; "$2_" >&3)"; ret=$?; printf "%q=%q;" "$1" "$out"; } 3>&1; echo "(exit $ret)"; }
capture() { eval "$(_capture "$@")"; }
e=2
function test1_() { passback e; }
function test1() {
e=4
echo "hello"
}
capture ret test1
echo "$ret"
echo "$e"
পছন্দসই প্রিন্ট করুন:
hello
4
এই সমাধান দ্রষ্টব্য:
- এছাড়াও কাজ
e=1000
করে।
$?
আপনার প্রয়োজন হলে সংরক্ষণ করে$?
শুধুমাত্র খারাপ পার্শ্ব প্রতিক্রিয়াগুলি হ'ল:
- এটি একটি আধুনিক প্রয়োজন
bash
।
- এটি বেশিরভাগ সময় কাঁটাচামচ করে।
- এটির জন্য টীকাটি দরকার (আপনার ফাংশনটির পরে নাম যুক্ত করা হয়েছে
_
)
- এটি ফাইল বর্ণনাকারী 3 ত্যাগ করে।
- আপনার যদি প্রয়োজন হয় তবে আপনি এটিকে অন্য এফডি তে পরিবর্তন করতে পারেন।
- ইন
_capture
শুধু সব occurances প্রতিস্থাপন 3
অন্য (উচ্চতর) নম্বর দিয়ে।
নিম্নলিখিত (যা বেশ দীর্ঘ, এর জন্য দুঃখিত) আশা করি ব্যাখ্যা করেছেন, কীভাবে এই রেসিপিটি অন্যান্য স্ক্রিপ্টগুলিতেও যুক্ত করা যায়।
সমস্যাটি
d() { let x++; date +%Y%m%d-%H%M%S; }
x=0
d1=$(d)
d2=$(d)
d3=$(d)
d4=$(d)
echo $x $d1 $d2 $d3 $d4
ফলাফল
0 20171129-123521 20171129-123521 20171129-123521 20171129-123521
যখন চেয়েছিল আউটপুট
4 20171129-123521 20171129-123521 20171129-123521 20171129-123521
সমস্যার কারণ
শেল ভেরিয়েবল (বা সাধারণভাবে বলতে গেলে, পরিবেশ) পিতামাতার প্রক্রিয়াগুলি থেকে শিশু প্রক্রিয়াগুলিতে প্রেরণ করা হয় তবে বিপরীতে নয়।
আপনি যদি আউটপুট ক্যাপচারিং করেন তবে এটি সাধারণত একটি সাবশেলে চালানো হয়, সুতরাং ব্যাক ভেরিয়েবলগুলি পাস করা কঠিন।
কেউ কেউ আপনাকে বলছেন যে এটি ঠিক করা অসম্ভব। এটি ভুল, তবে সমস্যাটি সমাধান করা এটি দীর্ঘদিনের জ্ঞান।
এটি কীভাবে সেরা সমাধান করা যায় তার বিভিন্ন উপায় রয়েছে, এটি আপনার প্রয়োজনের উপর নির্ভর করে।
এটি কীভাবে করা যায় সে সম্পর্কে এখানে ধাপে ধাপে গাইড।
প্যারেন্টাল শেলের মধ্যে ভেরিয়েবলগুলি পাস করা
প্যারেন্টাল শেলের কাছে ভেরিয়েবলগুলি ফেরত দেওয়ার উপায় রয়েছে। তবে এটি একটি বিপজ্জনক পথ, কারণ এটি ব্যবহার করে eval
। যদি ভুলভাবে করা হয়ে থাকে তবে আপনি অনেকগুলি খারাপ কাজের ঝুঁকি নিয়ে থাকেন। কিন্তু যদি সঠিকভাবে সম্পন্ন, এই পুরোপুরি নিরাপদ, প্রদত্ত সেখানে কোন বাগ সংশোধন করা হয় যে bash
।
_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }
d() { let x++; d=$(date +%Y%m%d-%H%M%S); _passback x d; }
x=0
eval `d`
d1=$d
eval `d`
d2=$d
eval `d`
d3=$d
eval `d`
d4=$d
echo $x $d1 $d2 $d3 $d4
প্রিন্ট
4 20171129-124945 20171129-124945 20171129-124945 20171129-124945
মনে রাখবেন যে এটি বিপজ্জনক জিনিসগুলির জন্যও কাজ করে:
danger() { danger="$*"; passback danger; }
eval `danger '; /bin/echo *'`
echo "$danger"
প্রিন্ট
; /bin/echo *
এটি এর কারণ printf '%q'
, যা এই জাতীয় সমস্ত কিছু উদ্ধৃত করে যে আপনি এটি শেল প্রসঙ্গে নিরাপদে পুনরায় ব্যবহার করতে পারবেন।
তবে এটি একটি একটি বেদনা ..
এটি কেবল কুরুচিপূর্ণ দেখায় না, এটি টাইপ করাও অনেক বেশি, তাই এটি ত্রুটিযুক্ত প্রবণ। শুধু একটি একক ভুল এবং আপনি ডুমড, ডান?
ঠিক আছে, আমরা শেল স্তরে আছি, সুতরাং আপনি এটি উন্নতি করতে পারেন। আপনি যে ইন্টারফেসটি দেখতে চান তা কেবল ভাবুন এবং তারপরে আপনি এটি প্রয়োগ করতে পারেন।
অগমেন্ট, শেল কীভাবে প্রক্রিয়াজাত করে
আসুন আমরা এক ধাপ পিছনে গিয়ে এমন কিছু এপিআই সম্পর্কে চিন্তা করি যা আমাদের সহজে প্রকাশ করতে দেয়, আমরা কী করতে চাই।
ঠিক আছে, আমরা d()
ফাংশনটি দিয়ে কী করতে চাই ?
আমরা আউটপুটটিকে একটি ভেরিয়েবলের মধ্যে ক্যাপচার করতে চাই। ঠিক আছে, এর ঠিক এর জন্য একটি এপিআই বাস্তবায়ন করা যাক:
: capture VARIABLE command args..
capture()
{
local -n output="$1"
shift
output="$("$@")"
}
এখন লেখার বদলে
d1=$(d)
আমরা লিখতে পারি
capture d1 d
ঠিক আছে, দেখে মনে হচ্ছে আমরা খুব বেশি কিছু পরিবর্তন করি নি, যেমন, আবার, ভেরিয়েবলগুলি d
প্যারেন্ট শেল থেকে ফিরে যায় না এবং আমাদের আরও কিছু টাইপ করতে হবে।
তবে এখন আমরা এটিতে শেলের পুরো শক্তিটি ফেলে দিতে পারি, কারণ এটি কোনও ফাংশনে সুন্দরভাবে আবৃত।
ইন্টারফেস পুনরায় ব্যবহার করার সহজ উপায় সম্পর্কে ভাবেন
দ্বিতীয় জিনিসটি হ'ল আমরা DRY হতে চাই (নিজেকে পুনরাবৃত্তি করবেন না)। সুতরাং আমরা অবশ্যই এর মতো কিছু টাইপ করতে চাই না
x=0
capture1 x d1 d
capture1 x d2 d
capture1 x d3 d
capture1 x d4 d
echo $x $d1 $d2 $d3 $d4
x
এখানে না শুধুমাত্র অপ্রয়োজনীয়, এটা ত্রুটি সবসময় সঠিক প্রেক্ষাপটে repeate প্রবণ। আপনি যদি কোনও স্ক্রিপ্টে এটি 1000 বার ব্যবহার করেন এবং তারপরে একটি ভেরিয়েবল যুক্ত করেন তবে? আপনি কলটি d
জড়িত রয়েছে এমন 1000 টি অবস্থানগুলিতে অবশ্যই পরিবর্তন করতে চান না ।
সুতরাং x
দূরে ছেড়ে যান, যাতে আমরা লিখতে পারি:
_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }
d() { let x++; output=$(date +%Y%m%d-%H%M%S); _passback output x; }
xcapture() { local -n output="$1"; eval "$("${@:2}")"; }
x=0
xcapture d1 d
xcapture d2 d
xcapture d3 d
xcapture d4 d
echo $x $d1 $d2 $d3 $d4
ফলাফল
4 20171129-132414 20171129-132414 20171129-132414 20171129-132414
এটি ইতিমধ্যে খুব ভাল দেখাচ্ছে। (তবে এখনও রয়েছে local -n
যা সাধারণ সাধারণ bash
3.x এ কাজ করে না )
পরিবর্তন এড়ানো d()
শেষ সমাধানটিতে কিছু বড় ত্রুটি রয়েছে:
d()
পরিবর্তন করা প্রয়োজন
xcapture
আউটপুট পাস করার জন্য এর কিছু অভ্যন্তরীণ বিশদ ব্যবহার করা দরকার ।
- মনে রাখবেন যে এই ছায়াগুলি (বার্ন) নামের একটি ভেরিয়েবল রয়েছে
output
, তাই আমরা কখনই এটি পিছনে যেতে পারি না।
- এর সাথে সহযোগিতা করা দরকার
_passback
আমরা কি এ থেকে মুক্তি পেতে পারি?
অবশ্যই, আমরা পারি! আমরা শেলের মধ্যে আছি, সুতরাং এটি সম্পন্ন করার জন্য আমাদের প্রয়োজনীয় সমস্ত কিছুই রয়েছে।
আপনি যদি কলটিতে কিছুটা ঘনিষ্ঠ হন তবে eval
আপনি দেখতে পাচ্ছেন যে, এই স্থানে আমাদের 100% নিয়ন্ত্রণ রয়েছে। "অভ্যন্তরে" eval
আমরা একটি সাব-শেলের মধ্যে রয়েছি, তাই পিতামাতার শেলের সাথে খারাপ কিছু করার ভয় না করে আমরা যা কিছু করতে চাই তা করতে পারি।
হ্যাঁ, দুর্দান্ত, সুতরাং সরাসরি এখন এর ভিতরে অন্য একটি মোড়ক যুক্ত করুন eval
:
_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }
_xcapture() { "${@:2}" > >(printf "%q=%q;" "$1" "$(cat)"); _passback x; }
xcapture() { eval "$(_xcapture "$@")"; }
d() { let x++; date +%Y%m%d-%H%M%S; }
x=0
xcapture d1 d
xcapture d2 d
xcapture d3 d
xcapture d4 d
echo $x $d1 $d2 $d3 $d4
প্রিন্ট
4 20171129-132414 20171129-132414 20171129-132414 20171129-132414
তবে এটির আবারও কিছু বড় ত্রুটি রয়েছে:
!DO NOT USE!
মার্কার, আছে এই খুব খারাপ জাতি শর্ত, যা আপনি সহজে দেখতে পাই না না থাকায়:
>(printf ..)
একটি ব্যাকগ্রাউন্ড কাজ। সুতরাং এটি _passback x
চলমান অবস্থায় এখনও কার্যকর হতে পারে ।
- আপনি নিজেই এটি দেখতে পারেন যদি আপনি
sleep 1;
আগে printf
বা যোগ করেন তবে _passback
।
_xcapture a d; echo
তারপরে যথাক্রমে আউটপুট x
বা a
প্রথম
- এর
_passback x
অংশ হওয়া উচিত নয় _xcapture
, কারণ এটি সেই রেসিপিটি পুনরায় ব্যবহার করা কঠিন করে তোলে।
- এছাড়াও আমাদের এখানে কিছু অপরিবর্তিত কাঁটাচামচ রয়েছে (দ্য
$(cat)
), তবে এই সমাধান হিসাবে !DO NOT USE!
আমি সংক্ষিপ্ততম পথটি নিয়েছি।
যাইহোক, এটি দেখায় যে, আমরা এটি করতে পারি, পরিবর্তিত d()
(এবং ছাড়া local -n
) ছাড়াই !
অনুগ্রহ করে নোট করুন যে আমাদের খুব প্রয়োজন _xcapture
হয় না, যেমনটি আমরা যথাযথভাবে লিখে ফেলতে পারি eval
।
তবে এটি করা সাধারণত খুব পঠনযোগ্য হয় না। এবং যদি আপনি কয়েক বছরের মধ্যে আপনার স্ক্রিপ্টে ফিরে আসেন তবে আপনি সম্ভবত খুব ঝামেলা ছাড়াই আবার এটি পড়তে সক্ষম হতে চান।
রেস ঠিক করুন
এবার আসুন রেসের শর্তটি ঠিক করি।
কৌতুকটি printf
এটি বন্ধ হয়ে যাওয়া অবধি অপেক্ষা করা হতে পারে এবং এটি আউটপুট x
।
এটি সংরক্ষণাগারভুক্ত করার অনেক উপায় রয়েছে:
- আপনি শেল পাইপ ব্যবহার করতে পারবেন না, কারণ পাইপগুলি বিভিন্ন প্রক্রিয়াতে চালিত হয়।
- কেউ অস্থায়ী ফাইল ব্যবহার করতে পারে,
- বা লক ফাইল বা ফিফোর মতো কিছু। এটি লক বা ফিফোর জন্য অপেক্ষা করতে দেয়,
- বা বিভিন্ন চ্যানেল, তথ্য আউটপুট, এবং তারপর কিছু সঠিক ক্রম আউটপুট একত্রিত।
শেষের পথটি অনুসরণ করা দেখতে দেখতে দেখতে পারা যায় (নোট করুন এটি printf
শেষ করে কারণ এটি এখানে আরও ভাল কাজ করে):
_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }
_xcapture() { { printf "%q=%q;" "$1" "$("${@:2}" 3<&-; _passback x >&3)"; } 3>&1; }
xcapture() { eval "$(_xcapture "$@")"; }
d() { let x++; date +%Y%m%d-%H%M%S; }
x=0
xcapture d1 d
xcapture d2 d
xcapture d3 d
xcapture d4 d
echo $x $d1 $d2 $d3 $d4
ফলাফল
4 20171129-144845 20171129-144845 20171129-144845 20171129-144845
কেন এটি সঠিক?
_passback x
সরাসরি কথা বলতে STDOUT।
- তবে, যেমন অভ্যন্তরীণ কমান্ডে STDOUT ক্যাপচার করা দরকার, আমরা প্রথমে এটিকে FD3 এ "সংরক্ষণ" করি (অবশ্যই আপনি অন্যদের ব্যবহার করতে পারেন) '3> & 1' দিয়ে এবং তারপরে এটি পুনরায় ব্যবহার করুন
>&3
।
$("${@:2}" 3<&-; _passback x >&3)
পরে শেষ _passback
, যখন subshell বন্ধ stdout- এ।
- সুতরাং এটি যতক্ষণ সময় নেয় তা বিবেচনা না করেই এর
printf
আগে ঘটতে পারে না ।_passback
_passback
- নোট করুন যে
printf
কমান্ডটি সম্পূর্ণ কমান্ডলাইন একত্রিত হওয়ার আগে কার্যকর করা হয় না, তাই আমরা printf
কীভাবে printf
কার্যকর করা হয় তা থেকে স্বাধীনভাবে আর্টফেসগুলি দেখতে পাচ্ছি না ।
অতএব প্রথমে _passback
মৃত্যুদন্ড কার্যকর করা, তারপর printf
।
এটি একটি স্থির ফাইল বর্ণনাকারী বলিদানের সাথে সাথে এই প্রতিযোগিতার সমাধান করে 3.
দয়া করে নোট করুন 3<&-
যা এফডি 3 কে ফাংশনে প্রেরণে সুরক্ষিত করে।
এটি আরও জেনেরিক করুন
_capture
পুনরায় d()
ব্যবহারযোগ্যতার দৃষ্টিকোণ থেকে অংশগুলি, যা সম্পর্কিত , যা খারাপ contains কীভাবে সমাধান করবেন?
ভাল, এটি আরও একটি জিনিস, একটি অতিরিক্ত ফাংশন, যা সংযুক্তের সাথে মূল ফাংশনটির নামে নামকরণ করা উচিত সঠিক জিনিসগুলি ফিরিয়ে আনতে হবে, পরিচয় করিয়ে কাঁচা উপায়ে এটি করুন _
।
এই ফাংশনটি আসল ফাংশনটির পরে ডাকা হয় এবং জিনিসগুলিকে বাড়িয়ে তুলতে পারে। এইভাবে এটি কিছু টিকা হিসাবে পড়া যায়, তাই এটি খুব পঠনযোগ্য:
_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }
_capture() { { printf "%q=%q;" "$1" "$("${@:2}" 3<&-; "$2_" >&3)"; } 3>&1; }
capture() { eval "$(_capture "$@")"; }
d_() { _passback x; }
d() { let x++; date +%Y%m%d-%H%M%S; }
x=0
capture d1 d
capture d2 d
capture d3 d
capture d4 d
echo $x $d1 $d2 $d3 $d4
এখনও মুদ্রণ
4 20171129-151954 20171129-151954 20171129-151954 20171129-151954
রিটার্ন-কোড অ্যাক্সেসের অনুমতি দিন
কিছুটা নিখোঁজ রয়েছে:
v=$(fn)
$?
কি fn
ফিরে আসে সেট করে । সুতরাং আপনি সম্ভবত এটিও চান যদিও এটির জন্য আরও কিছু বড় টুইট করা দরকার:
_passback() { while [ 1 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; return $1; }
passback() { _passback "$@" "$?"; }
_capture() { { out="$("${@:2}" 3<&-; "$2_" >&3)"; ret=$?; printf "%q=%q;" "$1" "$out"; } 3>&1; echo "(exit $ret)"; }
capture() { eval "$(_capture "$@")"; }
fails_() { passback x y; }
fails() { x=$1; y=69; echo FAIL; return 23; }
x=0
y=0
capture wtf fails 42
echo $? $x $y $wtf
প্রিন্ট
23 42 69 FAIL
উন্নতির জন্য এখনও অনেক জায়গা আছে
_passback()
সঙ্গে এলিমিনেট করা যেতে পারে passback() { set -- "$@" "$?"; while [ 1 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; return $1; }
_capture()
দিয়ে নির্মূল করা যেতে পারে capture() { eval "$({ out="$("${@:2}" 3<&-; "$2_" >&3)"; ret=$?; printf "%q=%q;" "$1" "$out"; } 3>&1; echo "(exit $ret)")"; }
সমাধানটি অভ্যন্তরীণভাবে কোনও ফাইল বর্ণনাকারীকে (এখানে 3) দূষিত করে। আপনার যদি এফডি পাস করার ঘটনা ঘটে তবে আপনার তা মনে রাখা দরকার need
নোট করুন যে bash
৪.১ এবং তার বেশি {fd}
কিছু অব্যবহৃত এফডি ব্যবহার করতে হবে।
(আশেপাশে এলে সম্ভবত আমি এখানে একটি সমাধান যুক্ত করব))
নোট করুন যে এ কারণেই আমি এটি আলাদা আলাদা ফাংশনে রাখি_capture
কারণ এগুলিকে এক লাইনে স্টাফ করা সম্ভব, তবে এটি পড়া এবং বোঝা আরও ক্রমশ শক্ত করে তোলে
সম্ভবত আপনি ডাকা ফাংশনটির এসটিডিআরআরও ক্যাপচার করতে চান। অথবা আপনি এমনকি ভেরিয়েবলগুলি থেকে এবং একাধিক ফাইলডেস্কিটার পাস এবং আউট করতে চান।
আমার এখনও কোনও সমাধান নেই, তবে এখানে একাধিক এফডি ধরার উপায় রয়েছে , তাই আমরা সম্ভবত এইভাবে চলকগুলিও আবার পাস করতে পারি।
এছাড়াও ভুলবেন না:
এটি অবশ্যই একটি শেল ফাংশন কল করবে, বাহ্যিক আদেশ নয়।
বাহ্যিক কমান্ডের বাইরে পরিবেশের ভেরিয়েবলগুলি পাস করার কোনও সহজ উপায় নেই। ( LD_PRELOAD=
যদিও এটি সম্ভব হওয়া উচিত!) তবে এটি তখন সম্পূর্ণ আলাদা।
শেষ কথা
এটিই একমাত্র সম্ভাব্য সমাধান নয়। এটি সমাধানের একটি উদাহরণ is
সর্বদা হিসাবে আপনার কাছে শেলের মধ্যে জিনিস প্রকাশের অনেক উপায় রয়েছে। সুতরাং উন্নত এবং আরও ভাল কিছু নির্দ্বিধায়।
এখানে উপস্থাপিত সমাধানটি নিখুঁত হওয়া থেকে অনেক দূরে:
- এটি মোটেও পরীক্ষামূলক ছিল না, তাই দয়া করে টাইপগুলি ক্ষমা করুন।
- উন্নতির জন্য অনেক জায়গা রয়েছে, উপরে দেখুন।
- এটি আধুনিক থেকে অনেকগুলি বৈশিষ্ট্য ব্যবহার করে
bash
, তাই সম্ভবত অন্যান্য শেলগুলি পোর্ট করা শক্ত is
- এবং এমন কিছু বিভ্রান্তি থাকতে পারে যা আমি ভাবিনি।
তবে আমি মনে করি এটি ব্যবহার করা বেশ সহজ:
- "লাইব্রেরি" এর 4 টি লাইন যুক্ত করুন।
- আপনার শেল ফাংশনটির জন্য "টিকা" এর 1 টি লাইন যুক্ত করুন।
- অস্থায়ীভাবে কেবল একটি ফাইলের বিবরণী উত্সর্গ করে।
- এবং প্রতিটি পদক্ষেপটি কয়েক বছর পরেও বোঝা সহজ হওয়া উচিত।