যখন আমার ফাংশনটি পাইপলাইনে ডাকা হয় তখন পরিবেশের ভেরিয়েবলগুলি সেট করা হয় না


10

পরিবেশের ভেরিয়েবলগুলি সেট করতে আমার নীচের পুনরাবৃত্ত ফাংশন রয়েছে:

function par_set {
  PAR=$1
  VAL=$2
  if [ "" != "$1" ]
  then
    export ${PAR}=${VAL}
    echo ${PAR}=${VAL}
    shift
    shift
    par_set $*
  fi
}

যদি আমি নিজেই এটি কল করি তবে এটি উভয়ই ভেরিয়েবল সেট করে এবং স্ট্যাডআউটের প্রতিধ্বনি দেয়:

$ par_set FN WORKS
FN=WORKS
$ echo "FN = "$FN
FN = WORKS

Stdout একটি ফাইলে পুনঃনির্দেশও কাজ করে:

$ par_set REDIR WORKS > out
cat out
REDIR=WORKS
$ echo "REDIR = "$REDIR
REDIR = WORKS

তবে, আমি যদি অন্য কোনও কমান্ডে স্টপআউট পাইপ করি তবে ভেরিয়েবল সেট হয় না:

$ par_set PIPE FAILS |sed -e's/FAILS/BARFS/'
PIPE=BARFS
$ echo "PIPE = "$PIPE
PIPE =

পাইপ কেন ভেরিয়েবল রফতানি থেকে ফাংশন আটকাবে? টেম্প ফাইল বা নামযুক্ত পাইপগুলি অবলম্বন না করে এটি ঠিক করার কোনও উপায় আছে কি?

মীমাংসিত:

গিলসকে ওয়ার্কিং কোড ধন্যবাদ:

par_set $(echo $*|tr '=' ' ') > >(sed -e's/^/  /' >> ${LOG})

এটি স্ক্রিপ্টটি এভাবে কল করার অনুমতি দেয়:

$ . ./script.sh PROCESS_SUB ROCKS PIPELINES=NOGOOD
$ echo $PROCESS_SUB
ROCKS
$ echo $PIPELINES
NOGOOD
$ cat log
7:20140606155622162731431:script.sh:29581:Parse Command Line parameters.  Params must be in matched pairs separated by one or more '=' or ' '.
  PROCESS_SUB=ROCKS
  PIPELINES=NOGOOD

প্রকল্পটি সম্পূর্ণ কোডে আগ্রহী হলে https://bitbucket.org/adalby/monitor-bash এ বিটবাকেটে হোস্ট করা হয়েছে ।

উত্তর:


8

একটি পাইপলাইন প্রত্যেকটি অংশ (যেমন পাইপের প্রতিটি পাশ) একটি পৃথক প্রক্রিয়া (ক subshell বলা হয়, যখন একটি শেল রান কাটাচামচ স্ক্রিপ্ট অংশ চালানোর জন্য একটি subprocess)। ইন par_set PIPE FAILS |sed -e's/FAILS/BARFS/', PIPEভেরিয়েবলটি সাব-প্রসেসে সেট করা থাকে যা পাইপের বাম-হাত চালায়। এই পরিবর্তনটি পিতামাতার প্রক্রিয়াতে প্রতিফলিত হয় না (এনভায়রনমেন্ট ভেরিয়েবলগুলি প্রক্রিয়াগুলির মধ্যে স্থানান্তরিত করে না, তারা কেবল উপ-প্রক্রিয়াগুলির দ্বারা উত্তরাধিকার সূত্রে প্রাপ্ত।

পাইপের বাম-হাত সর্বদা একটি সাবশেলে চলে। কিছু শেল (এটিটি কেএস, জেডএস) পিতামাতার শেলগুলিতে ডানদিকে চালায়; বেশিরভাগটি একটি সাবশেলে ডান হাত চালান।

আপনি যদি উভয়ই স্ক্রিপ্টের একটি অংশের আউটপুট পুনর্নির্দেশ করতে চান এবং সেই অংশটি প্যারেন্ট শেলটিতে, ksh / bash / zsh তে চালাতে চান তবে আপনি প্রক্রিয়া বিকল্প ব্যবহার করতে পারেন ।

par_set PROCESS SUBSTITUTION > >(sed s/ION/ED/)

যে কোনও পসিক্স শেল দিয়ে আপনি আউটপুটটিকে একটি নামী পাইপে পুনর্নির্দেশ করতে পারেন।

mkfifo f
<f grep NAMED= &
par_set NAMED PIPE >f

ওহ, এবং আপনি ভেরিয়েবল বিকল্পগুলির চারপাশে উদ্ধৃতিগুলি নিখোঁজ করছেন , আপনার কোড মতো জিনিসের বিরতি par_set name 'value with spaces' star '*'

export "${PAR}=${VAL}"

par_set "$@"

জয়ের বিকল্প প্রক্রিয়া! আমি জানতাম যে আমি একটি নামযুক্ত পাইপ বা টেম্প ফাইল ব্যবহার করতে পারি, তবে সেগুলি কুৎসিত, দুর্বল সামঞ্জস্য রয়েছে এবং স্ক্রিপ্টটি মারা গেলে পিছনে জগাখিচুড়ি রেখে যায় (ফাঁস শেষটির সাথে সহায়তা করে)। স্থান জিনিস ইচ্ছাকৃত। কনভেনশন দ্বারা, কমান্ড লাইনে প্রদত্ত ভেরিয়েবলগুলি নাম / মান জোড়া হয় এবং '=' এবং / অথবা '' দ্বারা পৃথক হয়।
অ্যান্ড্রু

3

এটি কাজ করে না কারণ পাইপের প্রতিটি পাশই একটি সাব-শেল-এ চলে এবং একটি সাব-শেলের মধ্যে bashসেট করা ভেরিয়েবলগুলি সেই সাবশেলের স্থানীয়।

হালনাগাদ:

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

কিছু তথ্যসূত্র:

http://mywiki.wooledge.org/BashFAQ/024
https://stackoverflow.com/q/15541321/3565972
https://stackoverflow.com/a/15383353/3565972
http://forums.opensuse.org/showthread .php / 458979-কীভাবে রপ্তানি পরিবর্তনশীল-ইন-subshell-ব্যাক-আউট টু পিতা বা মাতা


আমি ভেবেছিলাম এটি একটি সম্ভাবনা, তবে বর্তমান শেলটিতে ফাংশনটি সম্পাদন করা উচিত। আমি ফাংশনে একটি "প্রতিধ্বনি।" যুক্ত করে পরীক্ষা করেছি। par_set বিফল হয় | sed -e "S / ^ / sedpid = $$, fnpid = /" আউটপুট sedpid = 15957, fnpid = 15957.
অ্যান্ড্রু

@Andrew এই দেখুন stackoverflow.com/a/20726041/3565972 । স্পষ্টতই, $$পিতা-মাতা এবং শিশু শেল উভয়ের জন্য একই। $BASHPIDসাবসেল পিড পেতে আপনি ব্যবহার করতে পারেন । আমি যখন echo $$ $BASHPIDভিতরে par_setথাকি তখন আমি বিভিন্ন পাইড পাই।
সাওয়ান্টো

@ অ্যান্ড্রু এখনও একটি কর্মচেষ্টার সন্ধানের চেষ্টা করছেন, কিন্তু ব্যর্থ! =)
সাওয়ান্টো

@ Savanto-ধন্যবাদ। আমি জানতাম না যে প্রায় $$ বনাম AS বাশপিড বা পাইপ জোর করে সাবশেলগুলি জোর করে।
অ্যান্ড্রু

0

আপনি সাবশেলগুলি দেখিয়েছেন - এটি একটি পাইপলাইনের বাইরের শেলটিতে কিছুটা ফাইনগলিংয়ের সাথে পাওয়া যেতে পারে - তবে সমস্যার শক্ত অংশটি পাইপলাইনের সম্মতিতে করতে হবে

পাইপলাইনের সমস্ত প্রক্রিয়া সদস্যরা একবারে শুরু হয় এবং তাই সমস্যাটি যদি আপনি এটির মতো দেখে থাকেন তবে বুঝতে সমস্যাটি আরও সহজ হতে পারে:

{ sleep 1 ; echo $((f=1+2)) >&2 ; } | echo $((f))
###OUTPUT
0
...
3

পাইপলাইন প্রক্রিয়াগুলি ভেরিয়েবলের মানগুলি উত্তরাধিকারী হতে পারে না কারণ এগুলি ইতিমধ্যে বন্ধ হয়ে গেছে এবং ভেরিয়েবলটি সেট হওয়ার আগেই চলছে।

আপনার ফাংশনটির মূল বিষয়টি আমি আসলে বুঝতে পারি না - এটি exportইতিমধ্যে কী উদ্দেশ্যে কাজ করে ? নাকি ঠিক var=val? উদাহরণস্বরূপ, এখানে প্রায় একই পাইপলাইন আবার:

pipeline() { 
    { sleep 1
      echo "f=$((f=f+1+2))" >&3
    } | echo $((f)) >&2
} 3>&1

f=4 pipeline

###OUTPUT

4
...
f=7

এবং সাথে export:

export $(f=4 pipeline) ; pipeline

###OUTPUT:

4
7
...
f=10

সুতরাং আপনার জিনিস যেমন কাজ করতে পারে:

par_set $(echo PIPE FAILS | 
    sed 's/FAIL/WORK/;/./w /path/to/log')

যা কোনও ফাইলের sedআউটপুটে লগইন করে এবং এটি শেল-বিভক্ত হিসাবে আপনার ফাংশনে বিতরণ করবে "$@"

অথবা, বিকল্পভাবে:

$ export $(echo PIPE FAILS | sed 's/ FAIL/=WORK/')
$ par_set $PIPE TWICE_REMOVED
$ echo "WORKS = "$WORKS
WORKS = TWICE_REMOVED

আমি যদি আপনার ফাংশনটি লিখতে যাই তবে এটি সম্ভবত এটির মতো দেখায়:

_env_eval() { 
    while ${2+:} false ; do
       ${1:+export} ${1%%["${IFS}"]*}="${2}" || :
       shift 2
    done
}

এটি সত্য, তবে অপ্রাসঙ্গিক: পাইপলাইন শেষ হওয়ার পরে পাইপলাইনটি অপরদিকে নয়, অ্যান্ড্রু ভেরিয়েবলগুলি ব্যবহার করার চেষ্টা করছেন।
গিলস'স'-দুষ্ট হওয়া বন্ধ করুন '

@ গিলস - ভাল তিনি তা করতে পারেন। |pipeline | sh
মাইকজারভেজ

@ গিলস - আসলে আপনার প্রয়োজনও নেই sh। তিনি ইতিমধ্যে ব্যবহার করছেন export
মাইক্রোজার

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

1
@ মাইকজার্ভ- সমস্ত মন্তব্যের জন্য ধন্যবাদ। আমি প্রক্রিয়া প্রতিস্থাপনের জন্য গিলসের পরামর্শ নিয়েছিলাম, তবে আমার কোডটির পক্ষে তর্ক করা আমাকে আরও ভাল প্রোগ্রামার করে তোলে।
অ্যান্ড্রু
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.