ব্যাশে কোনও ফাংশনের মধ্যে কীভাবে বৈশ্বিক পরিবর্তনশীল পরিবর্তন করতে হয়?


109

আমি এটি নিয়ে কাজ করছি:

GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)

আমার নীচের মতো স্ক্রিপ্ট রয়েছে:

#!/bin/bash

e=2

function test1() {
  e=4
  echo "hello"
}

test1 
echo "$e"

যা ফেরত:

hello
4

তবে আমি যদি ফাংশনের ফলাফলটি একটি ভেরিয়েবলকে অর্পণ করি তবে গ্লোবাল ভেরিয়েবলটি পরিবর্তন করা eহয় না:

#!/bin/bash

e=2

function test1() {
  e=4
  echo "hello"
}

ret=$(test1)

echo "$ret"
echo "$e"

রিটার্নস:

hello
2

আমি এই ক্ষেত্রে ইওল এর ব্যবহারের কথা শুনেছি , তাই আমি এটি এখানে করেছি test1:

eval 'e=4'

তবে একই ফল।

আপনি আমাকে ব্যাখ্যা করতে পারেন কেন এটি সংশোধন করা হয়নি? আমি কীভাবে test1ফাংশনটির প্রতিধ্বনি সংরক্ষণ করতে পারি retএবং বৈশ্বিক পরিবর্তনশীলটিকেও সংশোধন করতে পারি?


আপনার কি হ্যালো ফিরতে হবে? এটি ফিরে আসার জন্য আপনি কেবল প্রতিধ্বনি করতে পারেন। বা আপনি যা চান তা প্রতিধ্বনি করুন এবং তারপরে ফলাফলটি বিশ্লেষণ করবেন?

উত্তর:


101

আপনি যখন কমান্ড সাবস্টিটিউশন (অর্থাত্ $(...)কনস্ট্রাক্ট) ব্যবহার করেন, আপনি একটি সাবশেল তৈরি করছেন। সাব্হেলগুলি তাদের প্যারেন্ট শেলগুলি থেকে ভেরিয়েবলের উত্তরাধিকারী, তবে এটি কেবলমাত্র একভাবে কাজ করে - একটি সাব-শেল তার প্যারেন্ট শেলের পরিবেশ পরিবর্তন করতে পারে না। আপনার পরিবর্তনশীলটি eএকটি সাব-শেলের মধ্যে সেট করা আছে তবে প্যারেন্ট শেল নয়। তার পিতামাতার কাছে সাব-শেল থেকে মানগুলি পাস করার দুটি উপায় রয়েছে। প্রথমত, আপনি stdout থেকে কিছু আউটপুট করতে পারেন, তারপরে এটি একটি কমান্ড প্রতিস্থাপনের সাথে ক্যাপচার করুন:

myfunc() {
    echo "Hello"
}

var="$(myfunc)"

echo "$var"

দেয়:

Hello

0-255 থেকে সংখ্যার মানের জন্য, আপনি returnপ্রস্থান স্থিতি হিসাবে নম্বরটি পাস করতে ব্যবহার করতে পারেন :

mysecondfunc() {
    echo "Hello"
    return 4
}

var="$(mysecondfunc)"
num_var=$?

echo "$var - num is $num_var"

দেয়:

Hello - num is 4

বিন্দুটির জন্য ধন্যবাদ, তবে আমাকে একটি স্ট্রিং অ্যারে ফিরিয়ে দিতে হবে এবং ফাংশনের মধ্যে আমাকে দুটি গ্লোবাল স্ট্রিং অ্যারেতে উপাদান যুক্ত করতে হবে।
হ্যারিসন 4

4
আপনি বুঝতে পেরেছেন যে আপনি যদি কেবলমাত্র কোনও ভেরিয়েবলের জন্য এটি না দিয়ে ফাংশনটি চালান তবে এর মধ্যে থাকা সমস্ত গ্লোবাল ভেরিয়েবল আপডেট হবে। স্ট্রিং অ্যারে ফিরিয়ে দেওয়ার পরিবর্তে, ফাংশনটিতে স্ট্রিং অ্যারের আপডেট না করে ফাংশনটি শেষ হওয়ার পরে এটি অন্য ভেরিয়েবলের কাছে বরাদ্দ করুন কেন?

@ জনডো: আপনি কোনও ফাংশন থেকে "স্ট্রিং অ্যারে" ফিরিয়ে দিতে পারবেন না। আপনি যা করতে পারেন তা হ'ল একটি স্ট্রিং মুদ্রণ করা। যাইহোক, আপনি এর মতো কিছু করতে পারেন:setarray() { declare -ag "$1=(a b c)"; }
ধনী

36

এই চাহিদা 4.1 bash যদি আপনি ব্যবহার {fd}বা local -n

বাকিদের বাশ 3.x এ কাজ করা উচিত আশা করি। কারণে আমি পুরোপুরি নিশ্চিত নই printf %q- এটি সম্ভবত ব্যাশ 4 বৈশিষ্ট্য।

সারসংক্ষেপ

পছন্দসই প্রভাবটি সংরক্ষণাগারভুক্ত করতে আপনার উদাহরণটি নিম্নরূপে সংশোধন করা যেতে পারে:

# Add following 4 lines:
_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

# Add following line, called "Annotation"
function test1_() { passback e; }
function test1() {
  e=4
  echo "hello"
}

# Change following line to:
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()ফাংশনটি দিয়ে কী করতে চাই ?

আমরা আউটপুটটিকে একটি ভেরিয়েবলের মধ্যে ক্যাপচার করতে চাই। ঠিক আছে, এর ঠিক এর জন্য একটি এপিআই বাস্তবায়ন করা যাক:

# This needs a modern bash 4.3 (see "help declare" if "-n" is present,
# we get rid of it below anyway).
: 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যা সাধারণ সাধারণ bash3.x এ কাজ করে না )

পরিবর্তন এড়ানো d()

শেষ সমাধানটিতে কিছু বড় ত্রুটি রয়েছে:

  • d() পরিবর্তন করা প্রয়োজন
  • xcaptureআউটপুট পাস করার জন্য এর কিছু অভ্যন্তরীণ বিশদ ব্যবহার করা দরকার ।
    • মনে রাখবেন যে এই ছায়াগুলি (বার্ন) নামের একটি ভেরিয়েবল রয়েছে output, তাই আমরা কখনই এটি পিছনে যেতে পারি না।
  • এর সাথে সহযোগিতা করা দরকার _passback

আমরা কি এ থেকে মুক্তি পেতে পারি?

অবশ্যই, আমরা পারি! আমরা শেলের মধ্যে আছি, সুতরাং এটি সম্পন্ন করার জন্য আমাদের প্রয়োজনীয় সমস্ত কিছুই রয়েছে।

আপনি যদি কলটিতে কিছুটা ঘনিষ্ঠ হন তবে evalআপনি দেখতে পাচ্ছেন যে, এই স্থানে আমাদের 100% নিয়ন্ত্রণ রয়েছে। "অভ্যন্তরে" evalআমরা একটি সাব-শেলের মধ্যে রয়েছি, তাই পিতামাতার শেলের সাথে খারাপ কিছু করার ভয় না করে আমরা যা কিছু করতে চাই তা করতে পারি।

হ্যাঁ, দুর্দান্ত, সুতরাং সরাসরি এখন এর ভিতরে অন্য একটি মোড়ক যুক্ত করুন eval:

_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }
# !DO NOT USE!
_xcapture() { "${@:2}" > >(printf "%q=%q;" "$1" "$(cat)"); _passback x; }  # !DO NOT USE!
# !DO NOT USE!
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ফিরে আসে সেট করে । সুতরাং আপনি সম্ভবত এটিও চান যদিও এটির জন্য আরও কিছু বড় টুইট করা দরকার:

# This is all the interface you need.
# Remember, that this burns FD=3!
_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 "$@")"; }

# Here is your function, annotated with which sideffects it has.
fails_() { passback x y; }
fails() { x=$1; y=69; echo FAIL; return 23; }

# And now the code which uses it all
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 টি লাইন যুক্ত করুন।
  • অস্থায়ীভাবে কেবল একটি ফাইলের বিবরণী উত্সর্গ করে।
  • এবং প্রতিটি পদক্ষেপটি কয়েক বছর পরেও বোঝা সহজ হওয়া উচিত।

4
আপনি দুর্দান্ত
এলিরান মালকা

14

হতে পারে আপনি কোনও ফাইল ব্যবহার করতে পারেন, ফাংশনের ভিতরে ফাইল লিখতে পারেন, এর পরে ফাইল থেকে পড়তে পারেন। আমি eঅ্যারেতে পরিবর্তিত হয়েছি । এই উদাহরণে ফাঁকাগুলি অ্যারেটি পড়ার সময় বিভাজক হিসাবে ব্যবহৃত হয়।

#!/bin/bash

declare -a e
e[0]="first"
e[1]="secondddd"

function test1 () {
 e[2]="third"
 e[1]="second"
 echo "${e[@]}" > /tmp/tempout
 echo hi
}

ret=$(test1)

echo "$ret"

read -r -a e < /tmp/tempout
echo "${e[@]}"
echo "${e[0]}"
echo "${e[1]}"
echo "${e[2]}"

আউটপুট:

hi
first second third
first
second
third

14

আপনি যা করছেন, আপনি পরীক্ষা 1 চালাচ্ছেন

$(test1)

একটি সাব-শেল (চাইল্ড শেল) এবং চাইল্ড শেল প্যারেন্টে কোনও কিছু সংশোধন করতে পারে না

আপনি এটি ব্যাশ ম্যানুয়ালটিতে খুঁজে পেতে পারেন

দয়া করে চেক করুন: বিষয়গুলি এখানে একটি সাব-শেলের ফলাফল


7

আমার অনুরূপ সমস্যা হয়েছিল, যখন আমি নিজের তৈরি টেম্প ফাইলগুলি স্বয়ংক্রিয়ভাবে মুছতে চাইতাম। আমি যে সমাধানটি নিয়ে এসেছি তা হ'ল কমান্ড সাবস্টিটিউশন ব্যবহার করা নয়, বরং ভেরিয়েবলের নামটি পাস করার জন্য, এটি চূড়ান্ত ফলাফলটি গ্রহণ করা উচিত the যেমন

#! /bin/bash

remove_later=""
new_tmp_file() {
    file=$(mktemp)
    remove_later="$remove_later $file"
    eval $1=$file
}
remove_tmp_files() {
    rm $remove_later
}
trap remove_tmp_files EXIT

new_tmp_file tmpfile1
new_tmp_file tmpfile2

সুতরাং, আপনার ক্ষেত্রে এটি হবে:

#!/bin/bash

e=2

function test1() {
  e=4
  eval $1="hello"
}

test1 ret

echo "$ret"
echo "$e"

"রিটার্ন মান" নিয়ে কাজ করে এবং এর কোনও বিধিনিষেধ নেই।


1

এটি হ'ল কমান্ড প্রতিস্থাপনটি একটি সাব-শেল-এ সঞ্চালিত হয়, সুতরাং যখন সাব-শেলগুলি ভেরিয়েবলগুলি উত্তরাধিকার সূত্রে প্রাপ্ত হয়, সাব-শেল শেষ হয়ে গেলে সেগুলিতে পরিবর্তনগুলি হারিয়ে যায়।

তথ্যসূত্র :

কমান্ড সাবস্টিটিউশন , প্রথম বন্ধনী যুক্ত কমান্ড এবং অ্যাসিনক্রোনাস কমান্ডগুলি শেল পরিবেশের সদৃশ একটি সাব-শেল পরিবেশে ডাকা হয়


@ জনডো আমি নিশ্চিত নই যে এটি সম্ভব। আপনাকে স্ক্রিপ্টটির নকশাটি পুনর্বিবেচনা করতে হবে।
কিছু প্রোগ্রামার

ওহ, তবে আমাকে একটি ফাংশনটির মধ্যে একটি গ্লোবাল অ্যারে আশ্বস্ত করা দরকার, যদি না হয় তবে আমাকে প্রচুর কোডটি পুনরাবৃত্তি করতে হবে (ফাংশনের কোডটি পুনরায় পুনরুদ্ধার করতে হবে -30 লাইনে- কল প্রতি এক বার 15 বার)। অন্য কোন উপায় নেই, তাই না?
হ্যারিসন 4

1

জটিল কার্যাবলী প্রবর্তন না করে এবং মূলটিকে ভারীভাবে সংশোধন না করেই এই সমস্যার একটি সমাধান হ'ল মানকে একটি অস্থায়ী ফাইলে সংরক্ষণ করে এবং প্রয়োজনে পড়তে / লিখতে হয়।

যখন ব্যাট টেস্টের ক্ষেত্রে একাধিকবার ডাকা বাশ ফাংশনকে উপহাস করতে হয়েছিল তখন এই পদ্ধতির সাহায্য করেছিল আমাকে।

উদাহরণস্বরূপ, আপনি থাকতে পারেন:

# Usage read_value path_to_tmp_file
function read_value {
  cat "${1}"
}

# Usage: set_value path_to_tmp_file the_value
function set_value {
  echo "${2}" > "${1}"
}
#----

# Original code:

function test1() {
  e=4
  set_value "${tmp_file}" "${e}"
  echo "hello"
}


# Create the temp file
# Note that tmp_file is available in test1 as well
tmp_file=$(mktemp)

# Your logic
e=2
# Store the value
set_value "${tmp_file}" "${e}"

# Run test1
test1

# Read the value modified by test1
e=$(read_value "${tmp_file}")
echo "$e"

অপূর্ণতা হ'ল আপনার বিভিন্ন ভেরিয়েবলের জন্য একাধিক টেম্প ফাইলের প্রয়োজন হতে পারে। এবং আপনার syncএকটি লিখন এবং পাঠ্য অপারেশনগুলির মধ্যে ডিস্কের বিষয়বস্তু অব্যাহত রাখতে কমান্ড জারি করার প্রয়োজন হতে পারে ।


-1

আপনি সর্বদা একটি নাম ব্যবহার করতে পারেন:

alias next='printf "blah_%02d" $count;count=$((count+1))'
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.